如何在Qt中发出跨线程信号?
Qt文档指出信号和插槽可以是direct
, queued
和auto
。
它还指出,如果拥有插槽的对象“生活”在一个与拥有信号的对象不同的线程中,发送这样的信号就像是发送消息 – 信号发送将立即返回,在目标线程的事件循环中将调用slot方法。
不幸的是,文档没有说明“生命”是什么,也没有可用的例子。 我已经尝试了下面的代码:
main.h:
class CThread1 : public QThread { Q_OBJECT public: void run( void ) { msleep( 200 ); std::cout << "thread 1 started" << std::endl; MySignal(); exec(); } signals: void MySignal( void ); }; class CThread2 : public QThread { Q_OBJECT public: void run( void ) { std::cout << "thread 2 started" << std::endl; exec(); } public slots: void MySlot( void ) { std::cout << "slot called" << std::endl; } };
main.cpp:
int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); CThread1 oThread1; CThread2 oThread2; QObject::connect( & oThread1, SIGNAL( MySignal() ), & oThread2, SLOT( MySlot() ) ); oThread1.start(); oThread2.start(); oThread1.wait(); oThread2.wait(); return a.exec(); }
输出是:
thread 2 started thread 1 started
MySlot()
永远不会被调用:(。我做错了什么?
你的代码有很多问题:
- 像埃文所说的发射关键字丢失
- 所有的对象都在主线程中,只有运行方法中的代码才会在其他线程中,这意味着MySlot插槽将在主线程中调用,我不确定这就是你想要的
- 您的插槽将永远不会被调用,因为主事件循环将永远不会启动:您的两个wait()调用只会在很长一段时间后超时(在这种情况发生之前,您可能会终止应用程序),我不认为这就是你想要的,无论如何,他们真的没有用在你的代码。
这个代码很可能会工作(虽然我没有testing过),我认为它做你想做的事情:
class MyObject : public QObject { Q_OBJECT public slots: void MySlot( void ) { std::cout << "slot called" << std::endl; } }; class CThread1 : public QThread { Q_OBJECT public: void run( void ) { std::cout << "thread 1 started" << std::endl; int i = 0; while(1) { msleep( 200 ); i++; if(i==1000) emit MySignal(); } } signals: void MySignal( void ); }; class CThread2 : public QThread { Q_OBJECT public: void run( void ) { std::cout << "thread 2 started" << std::endl; exec(); } }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); CThread1 oThread1; CThread2 oThread2; MyObject myObject; QObject::connect( & oThread1, SIGNAL( MySignal() ), & myObject, SLOT( MySlot() ) ); oThread2.start(); myObject.moveToThread(&oThread2) oThread1.start(); return a.exec(); }
现在MyObject将生活在thread2(感谢moveToThread)。
MySignal应该从thread1发送(以为我不确定那个,它可能是从主线程发送的,这并不重要)。
thread1中不需要事件循环,因为发送信号不需要事件循环。 thread2中需要一个事件循环(由exec()启动)来接收信号。
MySlot将在thread2中被调用。
不要inheritanceQt4.4+的QThread
虽然Aiua的答案很好,但我想指出QThread和Qt 4.6或4.7的一些问题。
本文总结: http : //blog.qt.io/blog/2010/06/17/youre-doing-it-wrong/
缺乏关于Qt的文档
不幸的是,这个问题源于对文档缺乏更新。 在Qt 4.4之前,QThread没有默认的run()实现,这意味着你必须inheritanceQThread才能使用它。
如果你使用Qt 4.6或4.7,那么你几乎肯定不应该inheritanceQThread。
使用moveToThread
获取插槽在工作线程中执行的关键是使用Aiua指出的moveToThread方法。