Qt——多线程中的信号与槽(二) 1.上节实验发现当槽函数是线程类中的成员时为什么依然不在本线程内被调用执行2.隐藏的问题对象依附于哪一个线程默认情况下对象依附于自身被创建的线程例如对象在主线程main()函数中被创建则依附于主线程对象的依附性与槽函数执行的关系默认情况下槽函数在其所依附的线程中被调用执行对象的依附性是否可以改变QObject::moveToThread用于改变对象的线程依附性使得对象的槽函数在依附的线程中被调用执行MyObject.h#ifndef MYOBJECT_H #define MYOBJECT_H #include QObject class MyObject : public QObject { Q_OBJECT public: explicit MyObject(QObject *parent nullptr); signals: protected slots: void getStarted(); void testSlot(); }; #endif // MYOBJECT_HMyObject.cpp#include MyObject.h #include QThread #include QDebug MyObject::MyObject(QObject *parent) : QObject{parent} { } void MyObject::getStarted() { qDebug() void MyObject::getStarted() tid QThread::currentThreadId(); } void MyObject::testSlot() { qDebug() void MyObject::testSlot() tid QThread::currentThreadId(); }TestThread.h#ifndef TESTTHREAD_H #define TESTTHREAD_H #include QThread class TestThread : public QThread { Q_OBJECT protected: void run(); public: explicit TestThread(QObject *parent nullptr); signals: void testSignal(); protected slots: void testSlot(); }; #endif // TESTTHREAD_HTestThread.cpp#include TestThread.h #include QDebug TestThread::TestThread(QObject *parent) : QThread{parent} { connect(this, SIGNAL(testSignal()), this, SLOT(testSlot())); } void TestThread::run() { qDebug() void TestThread::run() — — begin tid QThread::currentThreadId(); for(int i0; i5; i) { qDebug() void TestThread::run() i i; sleep(1); } emit testSignal(); qDebug() void TestThread::run() — — end; } void TestThread::testSlot() { qDebug() void TestThread::testSlot() tid QThread::currentThreadId(); }main.cpp#include QCoreApplication #include QDebug #include QThread #include TestThread.h #include MyObject.h int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); qDebug() main() tid QThread::currentThreadId(); TestThread t; MyObject m; QObject::connect(t, SIGNAL(started()), m, SLOT(getStarted())); QObject::connect(t, SIGNAL(testSignal()), m, SLOT(testSlot())); //m.moveToThread(t); //改变m线程的依附性依附于t t.start(); return QCoreApplication::exec(); }运行结果main() tid 0x30b8void TestThread::run() — — begin tid 0x1b78void TestThread::run() i 0void MyObject::getStarted() tid 0x30b8void TestThread::run() i 1void TestThread::run() i 2void TestThread::run() i 3void TestThread::run() i 4void TestThread::run() — — endvoid TestThread::testSlot() tid 0x30b8void MyObject::testSlot() tid 0x30b8将main.cpp中的m.moveToThread(t);取消注释后的运行结果主线程创建TestThread t和MyObject m连接信号槽t的started()→m的getStarted()跨线程t的testSignal()→m的testSlot()跨线程t的testSignal()→t的testSlot()同一对象同一线程m.moveToThread(t)→m移到子线程t.start()→ 启动子线程main() tid 0x3b40void TestThread::run() — — begin tid 0x16e4void TestThread::run() i 0void TestThread::run() i 1void TestThread::run() i 2void TestThread::run() i 3void TestThread::run() i 4void TestThread::run() — — endvoid TestThread::testSlot() tid 0x3b40我们发现改变m的依附性后m的槽函数没有被执行3.线程中的事件循环信号与槽的机制需要事件循环的支持QThread类中提供的exec()函数用于开启线程的事件循环只有事件循环开启槽函数才能在信号发送后被调用所以前提条件对象依附的线程开启了事件循环后置结果对象中的槽函数在依附的线程中被调用执行我们将TestThread.cpp中的run()函数中加入exec();语句后并且将t的依附性改为t的结果是main() tid 0x330void MyObject::getStarted() tid 0x6ecvoid TestThread::run() — — begin tid 0x6ecvoid TestThread::run() i 0void TestThread::run() i 1void TestThread::run() i 2void TestThread::run() i 3void TestThread::run() i 4void TestThread::testSlot() tid 0x6ecvoid MyObject::testSlot() tid 0x6ec研究这个的意义在于当信号的发送与对应槽函数的执行在不同线程中可能产生临界资源的竞争问题4.但是上述代码加入exec()后开启事件循环我们发现无法exec()后面的代码无法执行那么线程如何正常结束事件循环结束前exec()后的语句无法执行quit()和exit()函数用于结束事件循环quit()——exit(0)exec()的返回值由exit()参数决定无论事件循环是否开启信号发送后会直接进入对象所依附的事件队列然而只有开启了事件循环对应的槽函数才会在线程中被调用所以解决方案是在main.cpp中加入t.wait(8 * 1000);t.quit();即等待8秒如果线程还没有结束就向下执行5.什么时候需要在线程中开启事件循环事务性操作间断性IO操作等可以开启线程的事件循环每次操作通过发送信号的方式使得槽函数在子线程中执行示例写入文件FileWriter.cpp#ifndef FILEWRITER_H #define FILEWRITER_H #include QFile #include QObject #include QThread class FileWriter : public QObject { Q_OBJECT class Worker : public QThread { protected: void run(); }; QFile m_file; Worker m_worker; public: explicit FileWriter(QString file, QObject* parent 0); bool open(); void write(QString text); void close(); ~FileWriter(); signals: void doWrite(QString text); void doClose(); protected slots: void writeSlot(QString text); void closeSlot(); }; #endif // FILEWRITER_HFileWriter.h#include FileWriter.h #include QDebug #include QString void FileWriter::Worker::run() { qDebug() void FileWriter::Worker::run() - begin: tid currentThreadId(); exec(); qDebug() void FileWriter::Worker::run() - end; } FileWriter::FileWriter(QString file, QObject* parent) : QObject(parent), m_file(file) { connect(this, SIGNAL(doWrite(QString)), this, SLOT(writeSlot(QString))); connect(this, SIGNAL(doClose()), this, SLOT(closeSlot())); moveToThread(m_worker); m_worker.start(); } bool FileWriter::open() { return m_file.open(QIODevice::WriteOnly | QIODevice::Text); } void FileWriter::write(QString text) { qDebug() void FileWriter::write(QString text) tid QThread::currentThreadId(); emit doWrite(text); } void FileWriter::close() { qDebug() void FileWriter::close() tid QThread::currentThreadId(); emit doClose(); } void FileWriter::writeSlot(QString text) { qDebug() void FileWriter::writeSlot(QString text) tid QThread::currentThreadId(); m_file.write(text.toLatin1()); m_file.flush(); //强制将缓冲区中的数据立即写入物理存储设备所以write函数是一个很低效的事务 } void FileWriter::closeSlot() { qDebug() void FileWriter::closeSlot() tid QThread::currentThreadId(); m_file.close(); } FileWriter::~FileWriter() { m_worker.quit(); }main.cpp#include QCoreApplication #include QDebug #include QThread #include FileWriter.h int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); qDebug() main() tid QThread::currentThreadId(); FileWriter writer(C:\\Users\\聪\\Desktop\\1.txt); if( writer.open() ) { writer.write(hello); writer.write(11); writer.write(22); writer.close(); } return QCoreApplication::exec(); }运行结果main() tid 0x9d0void FileWriter::Worker::run() - begin: tid 0x2108void FileWriter::write(QString text) tid 0x9d0void FileWriter::write(QString text) tid 0x9d0void FileWriter::write(QString text) tid 0x9d0void FileWriter::close() tid 0x9d0void FileWriter::writeSlot(QString text) tid 0x2108void FileWriter::writeSlot(QString text) tid 0x2108void FileWriter::writeSlot(QString text) tid 0x2108void FileWriter::closeSlot() tid 0x2108

相关新闻

最新新闻

传统车牌识别系统VC++实现:图像处理与模式识别全流程解析

传统车牌识别系统VC++实现:图像处理与模式识别全流程解析

1. 项目概述与核心价值最近在整理老项目资料,翻出来一个十多年前用VC6.0写的车牌识别系统源代码。现在看,代码风格和架构可能有些“复古”,但里面关于图像处理、特征提取和模式识别的核心思想,对于想深入理解传统计算机视觉流程&a…

2026/7/15 6:19:03
解读如何制定符合企业战略的薪酬策略【附全文阅读】

解读如何制定符合企业战略的薪酬策略【附全文阅读】

适配人群(300 字内) 适配企业 HRD、薪酬绩效负责人、企管高管、财务管控人员、人力咨询顾问;初创 / 成长 / 成熟 / 改制各类企业经营管理者,尤其制造、快消、多元化集团负责人,用于薪酬体系重构、薪酬策略落地、年度调…

2026/7/15 6:19:03
C++实现工业CT滤波反投影算法:从原理到高性能代码实战

C++实现工业CT滤波反投影算法:从原理到高性能代码实战

1. 项目概述:从零实现一个工业级CT重建算法最近在整理一个老项目,发现几年前用C手搓的一个CT重建算法模块,虽然现在看代码有些地方可以优化,但整个从理论到实现的链路跑通了,效果也还过得去。当时做这个主要是为了验证…

2026/7/15 6:19:03
基于AI的情绪分析系统:从原理到实践部署指南

基于AI的情绪分析系统:从原理到实践部署指南

这次我们来看一个很有意思的项目——"股票跌停,足球买不中,上班不顺心,喜欢的女孩相亲了,我的人生利空出尽"。这个标题乍看像是个人情绪宣泄,但仔细分析会发现它其实反映了现代人面对多重压力时的心理状态&a…

2026/7/15 6:19:03
C++连接器与库文件实战指南:从原理到解决undefined reference

C++连接器与库文件实战指南:从原理到解决undefined reference

1. 项目概述:从“编译通过”到“运行成功”的最后一公里如果你写过C,大概率经历过这种场景:代码在IDE里编译(Compile)一帆风顺,绿色的小对勾亮起,心里一阵窃喜。但当你点击运行,或者…

2026/7/15 6:19:03
GLMcodingplan:面向生产环境的代码生成专用模型服务

GLMcodingplan:面向生产环境的代码生成专用模型服务

1. 项目概述:这不是一次普通上新,而是一次能力边界的试探性释放“智谱暂时限量发售 GLMcodingplan”——这句话在开发者社区里刚冒头时,我第一反应不是点开链接,而是翻出上周刚跑完的 GLM-4-Flash 压测日志,又调出本地…

2026/7/15 6:14:02

月新闻