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()
从来没有被称为:(.我做错了什么?
你的代码有很多问题:
就像Evan说的那样,emit关键字丢失了
所有对象都存在于主线程中,只有run方法中的代码存在于其他线程中,这意味着MySlot槽将在主线程中调用,我不确定这是你想要的
你的插槽永远不会被调用,因为主事件循环永远不会被启动:你的两次调用wait()只会在很长一段时间后超时(你可能会在发生这种情况之前杀死你的应用程序)并且我不认为这也是你想要的,无论如何它们在你的代码中真的没用.
这段代码最有可能工作(虽然我没有测试过),我认为它可以做你想做的事情:
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中调用.
虽然Aiua的答案很好,但我想指出QThread和Qt 4.6或4.7的一些问题.
本文总结如下:http://blog.qt.io/blog/2010/06/17/youre-doing-it-wrong/
不幸的是,问题源于缺乏文档更新.在Qt 4.4之前,QThread没有默认的run()实现,这意味着你必须继承QThread才能使用它.
如果你正在使用Qt 4.6或者4.7,那么你几乎可以肯定应该不是继承的QThread.
获取插槽在工作线程中执行的关键是使用moveToThread方法,如Aiua指出的那样.