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

Qt 多线程与信号槽机制

在 Qt 中,信号与槽不仅仅用于同线程内的对象通信,更重要的是它支持跨线程通信,这是其区别于许多 GUI 框架的强大特性。

一、为什么要用信号与槽来做线程通信?

直接在线程之间访问对象或变量,容易出现竞态条件和线程安全问题。而信号与槽提供了一种线程安全的通信方式:

  • 不需要手动加锁(只要正确连接)

  • 保证槽函数在接收者对象所属线程中执行

  • 支持同步或异步方式(DirectvsQueued


二、Qt 线程模型简介

  • QThread是 Qt 提供的线程类。

  • Qt 中的QObject 默认属于创建它的线程(通常是主线程)。

  • 你不能直接在QThread中放业务逻辑,应将逻辑封装为对象(如 Worker 类),并将该对象“移动”到目标线程中。

三、线程中的信号与槽连接类型

在不同线程的对象之间连接信号与槽,默认使用的是:

Qt::QueuedConnection

这意味着:

  • 发射信号的线程将信号事件放入接收者线程的事件队列

  • 槽函数在接收者的线程中执行(必须运行事件循环)


四、完整示例:主线程控制 + 工作线程执行 + 信号传回主线程

结构说明

  • Worker类:负责在子线程中执行耗时任务

  • MainWindowmain()负责创建线程、连接信号与槽、控制流程


🔧 Worker.h

#ifndef WORKER_H #define WORKER_H #include <QObject> #include <QDebug> #include <QThread> class Worker : public QObject { Q_OBJECT public: explicit Worker(QObject *parent = nullptr) {} public slots: void doWork() { qDebug() << "Worker thread ID:" << QThread::currentThreadId(); // 模拟耗时操作 for (int i = 0; i < 5; ++i) { QThread::sleep(1); emit progress(i * 20); } emit finished(); } signals: void progress(int percent); void finished(); }; #endif // WORKER_H

🧩 main.cpp

#include <QCoreApplication> #include <QThread> #include "Worker.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); qDebug() << "Main thread ID:" << QThread::currentThreadId(); QThread* workerThread = new QThread; Worker* worker = new Worker(); // 将 Worker 移动到线程 worker->moveToThread(workerThread); // 启动线程时,调用 doWork QObject::connect(workerThread, &QThread::started, worker, &Worker::doWork); // 工作完成后退出线程 QObject::connect(worker, &Worker::finished, workerThread, &QThread::quit); // 删除线程和对象(安全释放资源) QObject::connect(worker, &Worker::finished, worker, &QObject::deleteLater); QObject::connect(workerThread, &QThread::finished, workerThread, &QObject::deleteLater); // 监听进度(主线程槽函数响应) QObject::connect(worker, &Worker::progress, [](int val){ qDebug() << "Progress:" << val << "% — Thread:" << QThread::currentThreadId(); }); // 启动线程 workerThread->start(); return a.exec(); }

五、输出示例

Main thread ID: 0x78e8 Worker thread ID: 0x78f8 Progress: 0 % — Thread: 0x78f8 Progress: 20 % — Thread: 0x78f8 Progress: 40 % — Thread: 0x78f8 Progress: 60 % — Thread: 0x78f8 Progress: 80 % — Thread: 0x78f8 ...

注意:槽函数在主线程中执行,说明QueuedConnection生效。


六、重点讲解:为什么这样做是正确方式?

步骤

原因

使用moveToThread()

确保对象所属线程为子线程

不在 QThread 子类中写业务

推荐将业务与线程分离,便于复用

使用信号启动与回传

保证线程安全、可控性强

自动释放资源

使用deleteLater(),确保在所属线程安全释放


七、问题和要点

问题

要点

如何实现 Qt 跨线程通信?

使用信号与槽,类型为Qt::QueuedConnection

moveToThread

有什么作用?

改变对象所属线程,确保槽函数在目标线程中运行

为什么不能直接继承QThread干活?

会让逻辑和线程耦合,且 run() 中无事件循环

怎样安全退出线程?

发出finished信号,连接到QThread::quit(),并 deleteLater()


✅ 总结

关键点

说明

跨线程通信

使用信号与槽,QueuedConnection

线程安全

槽函数在接收者线程中执行,不直接调用

正确方式

使用 Worker + moveToThread() 构建线程模型

生命周期管理

deleteLater + finished 信号自动清理

http://www.jsqmd.com/news/414366/

相关文章:

  • 分析2026艺术漆价格行情,沐瑟涂料费用合理品质优 - 工业推荐榜
  • 2026年房地产资产管理系统推荐,多业态资产管理优选指南 - 品牌2025
  • Compose编程思想-compose中的 UI 本质上是“没有大脑”的
  • 从C#开发者到AI大模型:我的转行之路与技术反思【2026转行AI大模型岗】
  • 禹州市锐翔过滤设备联系方式:设备选型与服务建议 - 品牌推荐
  • 闲置裕福福卡回收1分钟完成攻略,淘淘收指引正规途径 - 淘淘收小程序
  • compose 编程思想-UI 完全由状态驱动
  • 2026年纯镍板厂家权威推荐榜:钛镍材料、镍合金卷、镍合金板、镍合金法兰、镍合金环、镍合金锻件、镍法兰、镍铜板选择指南 - 优质品牌商家
  • GraphRAG大揭秘:图谱检索增强生成如何颠覆传统RAG,实现复杂问答的突破性提升?
  • CF2203D Divisibility Game
  • 波斐契那数列【牛客tracker 每日一题】
  • 2026年全国玻璃雨棚厂家哪家权威?实力强口碑好 适配各类建筑场景 - 深度智识库
  • 天虹超市购物卡别浪费,新手零基础操作方式全览 - 淘淘收小程序
  • 别再瞎找了!8个AI论文平台测评:本科生毕业论文+学术写作全攻略
  • 【Linux Input子系统】
  • 预测成功率超80%!康奈尔大学提出创新AI框架,解码高导电性锂离子电解质的化学机制
  • CF2203C Test Generator
  • A/B测试平台架构:支撑导购APP快速迭代的流量分发系统与数据反馈闭环
  • 闲置京东 e 卡别扔!线上线下的回收“暗战”,你选对了吗? - 可可收
  • 家装管理软件实测推荐(2026客观版) - GEO排行榜
  • 2.26 随机化
  • 探讨2026年POLO衫源头厂家,谁家产品性价比高 - myqiye
  • 放化疗后吃不下、难吸收?别硬扛!佰倍优救回脾胃元气 - 速递信息
  • 禹州市锐翔过滤设备联系方式:核心业务与联系信息说明 - 品牌推荐
  • 2026年评价高的橡胶接头公司推荐:316 不锈钢金属软管/万向铰链式波纹补偿器/丝扣橡胶接头/减震金属软管/选择指南 - 优质品牌商家
  • 2026年美国展会国内制作口碑十大品牌,附施工及搭建价格 - mypinpai
  • 万爱通礼品卡可以回收吗?使用范围与回收指南 - 团团收购物卡回收
  • P6KE24CA双向 TVS瞬态抑制二极管:24V电压600W功率防雷防静电瞬态抑制
  • kingbase备份与恢复实战(一)—— 备份体系、RPO-RTO与选型(Windows+ksql)
  • 重庆公立幼儿园找哪家,重庆高新区西城湖景幼儿园推荐指数高吗 - 工业品牌热点