当前位置: 首页 > news >正文

系统讨论Qt的并发编程——逻辑上下文的分类

目录

前言

首先,讨论Qt里常见的三种上下文

同一线程的串行执行

同一线程的异步执行

多线程的执行

moveToThread办法


前言

笔者最近看了一个具备一定启发性质的Qt教程,在这里,笔者打算整理一下自己的笔记。分享在这里.

首先,讨论Qt里常见的三种上下文

Qt在逻辑层上,笔者认为可分成三种上下文:同线程的同步,同线程的异步和多线程。

一个典型的同线程之间的同步,说的是我们的处理在执行流上,是串行的。

main ---> A -----> B ------> C

比如说,A函数,B函数和C函数在上下文中,串行的执行。这样的上下文,非常的可靠,每一个指令流都串行的访问数据,不会出现数据竞争的问题,但是代价就是——非常的慢。笔者三年的编程经验告诉自己——这样的编程上下文,适用于流程在时序上非常严密的场景。

一个典型的同线程异步,事情就看起来很有趣了。实际上看起来像这样。

这样的技术,任何一个学习过OS的都知道,实际上是在应用层上对这个线程实现了分片,换而言之,我们在这个线程上实现了逻辑并行,物理串行的效果——看起来我们的代码在并发的执行,但是实际上是一个线程快无影的完成一大堆工作。所以,这样的编程范式属于高响应要求的场景,或者说,我们对性能谈不上太高的要求,只需要他们看起来在同时执行。

这个场景,就是真并发的场景了,不管怎么说,我们真的有多个线程执行多个代码流,我们的代码上下文被托付给了操作系统层级的线程完成我们的工作。我们老生长谈的数据竞争并发安全,就是在讨论这里的事情。

同一线程的串行执行

#include <QCoreApplication>
#include <QThread>
​
void workA() {qInfo() << "I am handling Work A" << "Thread:" << QThread::currentThread();QThread::currentThread()->sleep(1);qInfo() << "Work A Finished";
}
​
void workB() {qInfo() << "I am handling Work B" << "Thread:" << QThread::currentThread();QThread::currentThread()->sleep(1);qInfo() << "Work B Finished";
}
​
void workC() {qInfo() << "I am handling Work C" << "Thread:" << QThread::currentThread();QThread::currentThread()->sleep(1);qInfo() << "Work C Finished";
}
​
int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);QThread::currentThread()->setObjectName("Thread Main");workA();workB();workC();return a.exec();
}

这个就是一个例子,我们的任务ABC按照串行依次执行代码。看我们的输出,就是这个主线程在依次的做任务ABC。

I am handling Work A Thread: QThread(0x1f0730e2860, name = "Thread Main")
Work A Finished
I am handling Work B Thread: QThread(0x1f0730e2860, name = "Thread Main")
Work B Finished
I am handling Work C Thread: QThread(0x1f0730e2860, name = "Thread Main")
Work C Finished

同一线程的异步执行

事实上,对于一些使用了QT类的场景,同一线程的异步执行仍然非常常见。一个经典的例子就是我们使用QTimer的singleshot办法触发一个函数的执行。你可以看到,我们实际上根本没有直接的调用,但是async_workA由于timer事件的通知作为槽执行了

#include <QCoreApplication>
#include <QThread>
#include <QTimer>
​
void async_workA() {qInfo() << "Lets's see the current thread: "<< QThread::currentThread()->objectName();QThread::currentThread()->sleep(1);qInfo() << "And A work done:)";
}
​
int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);QThread::currentThread()->setObjectName("Main Thread");QTimer m;m.singleShot(1000, &async_workA);
​qInfo() << "Main Thread: " << QThread::currentThread()->objectName();qInfo() << "has reached its end!";return a.exec();
}
 

多线程的执行

现在我们开始上难度,那就是多线程的执行。

TestObject.cpp

#include "TestObject.h"
​
#include <QDebug>
#include <QThread>
#include <QTimer>
TestObject::TestObject(QObject *parent) : QObject{parent} {}
​
void TestObject::runMe() {qInfo() << QThread::currentThread()->objectName() << " Running";QTimer::singleShot(1000, this, &TestObject::internel_shot);qInfo() << QThread::currentThread()->objectName() << " Finish";
}
​
void TestObject::internel_shot() { qInfo() << "Shot"; }

Main.cpp

#include <QCoreApplication>
#include <QThread>
​
#include "TestObject.h"
int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);
​QThread::currentThread()->setObjectName("Main Thread");
​qInfo() << "Ready to shot a thread";
​QThread thread;thread.setObjectName("Thread Worker");
​TestObject test;
​test.moveToThread(&thread);
​QObject::connect(&thread, &QThread::started, &test, &TestObject::runMe);
​thread.start();
​qInfo() << "Finish " << QThread::currentThread()->objectName();
​return a.exec();
}

这里有一个新的方法,简单说一下:

moveToThread办法

moveToThread 是 Qt 中用于将对象移到指定线程的函数。必须说明的是——我们的QT信号与槽机制是不跨线程的,也就是说,我们没办法使用信号与槽机制链接在A线程的a对象的信号与在B线程的b对象的槽。对于非 GUI 类的对象,可以通过调用 moveToThread 将它们从主线程或其他线程转移到目标线程。这样,目标线程就会负责该对象的事件处理和信号槽连接。

这样,我们就会将我们的TestObject放置到我们的新线程中,换而言之,任何一个将会在B线程工作但是创建于A线程的物体,请使用这个方法。

相关文章:

系统讨论Qt的并发编程——逻辑上下文的分类

目录 前言 首先&#xff0c;讨论Qt里常见的三种上下文 同一线程的串行执行 同一线程的异步执行 多线程的执行 moveToThread办法 前言 笔者最近看了一个具备一定启发性质的Qt教程&#xff0c;在这里&#xff0c;笔者打算整理一下自己的笔记。分享在这里. 首先&#xff0c…...

《Linux Shell 脚本深度探索:原理与高效编程》

1. 基本结构 Shebang 行 #!/bin/bash # Shebang 行指定了脚本使用的解释器。 /bin/bash 表示使用 Bash 解释器执行脚本。 注释 # 这是注释&#xff0c;不会被执行 2. 变量 定义变量 variable_namevalue # 不需要加 $ 来定义变量。 # 变量名不能包含空格或特殊字符。 访…...

深入剖析:基于红黑树实现自定义 map 和 set 容器

&#x1f31f; 快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。&#x1f31f; 在 C 标准模板库&#xff08;STL&#xff09;的大家庭里&#xff0c;map和set可是超级重要的关联容器成员呢&#x1f60e;&#x…...

在大数据项目中如何设计和优化数据模型

在大数据项目中&#xff0c;设计和优化数据模型是一个涉及多个步骤和维度的复杂过程。以下是我通常采取的方法&#xff1a; 一、数据模型设计 明确业务需求&#xff1a; 深入了解项目的业务场景和目标&#xff0c;明确数据模型需要解决的具体问题。与业务团队紧密合作&#xf…...

JavaScript querySelector()、querySelectorAll() CSS选择器解析(DOM元素选择)

文章目录 基于querySelector系列方法的CSS选择器深度解析一、方法概述二、基础选择器类型1. 类型选择器2. ID选择器3. 类选择器4. 属性选择器 三、组合选择器1. 后代组合器2. 子元素组合器3. 相邻兄弟组合器4. 通用兄弟组合器 四、伪类与伪元素1. 结构伪类2. 状态伪类3. 内容伪…...

Linux系统中处理子进程的终止问题

1. 理解子进程终止的机制 在Unix/Linux系统中&#xff0c;当子进程终止时&#xff0c;会向父进程发送一个SIGCHLD信号。父进程需要捕捉这个信号&#xff0c;并通过调用wait()或waitpid()等函数来回收子进程的资源。这一过程被称为“回收僵尸进程”。 如果父进程没有及时调用w…...

Docker 不再难懂:快速掌握容器命令与架构原理

1. Docker 是容器技术的一种 容器&#xff08;Container&#xff09;概述 容器&#xff08;Container&#xff09;是一种轻量级的虚拟化技术&#xff0c;它将应用程序及其所有依赖环境打包在一个独立的、可移植的运行时环境中。容器通过操作系统级的虚拟化提供隔离&#xff0…...

取消票证会把指定的票证从数据库中删除,同时也会把票证和航班 等相关表中的关联关系一起删除。但在删除之前,它会先检查当前用户是否拥有这张票

在做航班智能客服问答系统时会遇到取消票证的场景&#xff0c;这里涉及数据库的操作时会把指定的票证从数据库中删除&#xff0c;同时也会把票证和航班等相关表中的关联关系一起删除。但在删除之前&#xff0c;需要先检查当前用户是否拥有这张票&#xff0c;只有票主才有权限取…...

力扣-贪心-763 划分字母区间

思路 先统计字符串中每一个字母出现的最后下标&#xff0c;然后从end初始化为第一个字母出现的最后下标&#xff0c;在i<end时&#xff0c;不断更新end&#xff0c;因为一旦囊括新的字母就最起码要遍历到新字母出现的最后下标&#xff0c;在i>end时&#xff0c;说明遍历…...

【Redis 原理】网络模型

文章目录 用户空间 && 内核空间阻塞IO非阻塞IO信号驱动IO异步IOIO多路复用selectpollepoll Web服务流程Redis 网络模型Redis单线程网络模型的整个流程Redis多线程网络模型的整个流程 用户空间 && 内核空间 为了避免用户应用导致冲突甚至内核崩溃&#xff0c;用…...

cpp中的继承

一、继承概念 在cpp中&#xff0c;封装、继承、多态是面向对象的三大特性。这里的继承就是允许已经存在的类&#xff08;也就是基类&#xff09;的基础上创建新类&#xff08;派生类或者子类&#xff09;&#xff0c;从而实现代码的复用。 如上图所示&#xff0c;Person是基类&…...

DeepSeek全栈接入指南:从零到生产环境的深度实践

第一章:DeepSeek技术体系全景解析 1.1 认知DeepSeek技术生态 DeepSeek作为新一代人工智能技术平台,构建了覆盖算法开发、模型训练、服务部署的全链路技术栈。其核心能力体现在: 1.1.1 多模态智能引擎 自然语言处理:支持文本生成(NLG)、语义理解(NLU)、情感分析等计算…...

CSS 真的会阻塞文档解析吗?

在网页开发领域&#xff0c;一个常见的疑问是 CSS 是否会阻塞文档解析。理解这一问题对于优化网页性能、提升用户体验至关重要。要深入解答这个问题&#xff0c;需要从浏览器渲染网页的原理说起。 浏览器渲染网页的基本流程 浏览器在接收到 HTML 文档后&#xff0c;会依次进行…...

大模型的UI自动化:Cline 使用Playwright MCP Server完成测试

大模型的UI自动化:Cline 使用Playwright MCP Server完成测试 MCP MCP(Model Context Protocol),是一个开发的协议,标准化了应用程序如何为大模型提供上下文。MCP提供了一个标准的为LLM提供数据、工具的方式,使用MCP会更容易的构建Agent或者是基于LLM的复杂工作流。 最近…...

碰撞检测 | 图解凸多边形分离轴定理(附ROS C++可视化)

目录 0 专栏介绍1 凸多边形碰撞检测2 多边形判凸算法3 分离轴定理(SAT)4 算法仿真与可视化4.1 核心算法4.2 仿真实验 0 专栏介绍 &#x1f525;课设、毕设、创新竞赛必备&#xff01;&#x1f525;本专栏涉及更高阶的运动规划算法轨迹优化实战&#xff0c;包括&#xff1a;曲线…...

Python 基本数据类型

目录 1. 字符串&#xff08;String&#xff09; 2. 列表&#xff08;List&#xff09; 3. 字典&#xff08;Dictionary&#xff09; 4. 集合&#xff08;Set&#xff09; 5. 数字&#xff08;Number&#xff09; 6. 布尔值&#xff08;Boolean&#xff09; 1. 字符串&…...

突破“第一崇拜“:五维心理重构之路

一、视频介绍 在这个崇尚"第一"的时代&#xff0c;我们如何找到自己的独特价值&#xff1f;本视频将带您踏上五维心理重构之旅&#xff0c;从诗意人生的角度探讨如何突破"圣人之下皆蝼蚁"的局限。我们将穿越人生的不同阶段&#xff0c;从青春的意气风发到…...

KubeKey一键安装部署k8s集群和KubeSphere详细教程

目录 一、KubeKey简介 二、k8s集群KubeSphere安装 集群规划 硬件要求 Kubernetes支持版本 操作系统要求 SSH免密登录 配置集群时钟 所有节点安装依赖 安装docker DNS要求 存储要求 下载 KubeKey 验证KubeKey 配置集群文件 安装集群 验证命令 登录页面 一、Ku…...

UE5网络通信架构解析

文章目录 前言一、客户端-服务器架构&#xff08;C/S Model&#xff09;二、对等网络架构&#xff08;P2P&#xff0c;非原生支持&#xff09;三、混合架构&#xff08;自定义扩展&#xff09;四、UE5网络核心机制 前言 UE5的网络通信主要基于客户端-服务器&#xff08;C/S&am…...

实验3 知识表示与推理

实验3 知识表示与推理 一、实验目的 &#xff08;1&#xff09;掌握知识和知识表示的基本概念&#xff0c;理解其在AI中的深刻含义与意义&#xff1b; &#xff08;2&#xff09;熟悉AI中常用的知识表示方法的优缺点及其应用场景&#xff1b; &#xff08;3&#xff09;掌握产…...

ES6从入门到精通:前言

ES6简介 ES6&#xff08;ECMAScript 2015&#xff09;是JavaScript语言的重大更新&#xff0c;引入了许多新特性&#xff0c;包括语法糖、新数据类型、模块化支持等&#xff0c;显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var&#xf…...

golang循环变量捕获问题​​

在 Go 语言中&#xff0c;当在循环中启动协程&#xff08;goroutine&#xff09;时&#xff0c;如果在协程闭包中直接引用循环变量&#xff0c;可能会遇到一个常见的陷阱 - ​​循环变量捕获问题​​。让我详细解释一下&#xff1a; 问题背景 看这个代码片段&#xff1a; fo…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

Nginx server_name 配置说明

Nginx 是一个高性能的反向代理和负载均衡服务器&#xff0c;其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机&#xff08;Virtual Host&#xff09;。 1. 简介 Nginx 使用 server_name 指令来确定…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序

一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/

使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题&#xff1a;docker pull 失败 网络不同&#xff0c;需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

基于matlab策略迭代和值迭代法的动态规划

经典的基于策略迭代和值迭代法的动态规划matlab代码&#xff0c;实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...

iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈

在日常iOS开发过程中&#xff0c;性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期&#xff0c;开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发&#xff0c;但背后往往隐藏着系统资源调度不当…...

【Go语言基础【12】】指针:声明、取地址、解引用

文章目录 零、概述&#xff1a;指针 vs. 引用&#xff08;类比其他语言&#xff09;一、指针基础概念二、指针声明与初始化三、指针操作符1. &&#xff1a;取地址&#xff08;拿到内存地址&#xff09;2. *&#xff1a;解引用&#xff08;拿到值&#xff09; 四、空指针&am…...