How to emit a cross-thread signal in Qt?

The Qt documentation says that signals and slots can be direct , queued and auto .

He also stated that if an object that owns a "life" slot in a stream other than an object that owns the signal emits such a signal, it will be like a send message - the emit signal will return instantly, and the slot method will be called in the target loop of the stream's events ,

Unfortunately, the documentation does not indicate what β€œlife” means, and there are no examples. I tried the following code:

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(); } 

Exit:

 thread 2 started thread 1 started 

MySlot() never called :( What am I doing wrong?

+58
c ++ qt signals signals-slots qt-signals
Mar 12 '09 at 11:38
source share
3 answers

There are quite a few problems in your code:

  • as Evan said, the emit keyword is missing
  • all your objects live in the main thread, only the code in the launch methods lives in other threads, which means that the MySlot slot will be called in the main thread, and I'm not sure what you want
  • your slot will never be called, since the main event loop has never been triggered: your two wait () calls will only timeout after a very long time (and you will probably kill your application before this happens), and I don’t think that you also want, anyway, they really don't make sense in your code.

This code is likely to work (although I have not tested it), and I think it does what you want:

 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(); } 

Now MyObject will live in thread2 (thanks to moveToThread).

MySignal should be sent from thread1 (thought that I was not sure about this, it can be sent from the main thread, it does not matter).

Stream 1 does not require an event loop, since an event loop is not required to emit a signal. An event loop is needed in thread2 (using exec ()) to receive a signal.

MySlot is called in thread2.

+46
Mar 12 '09 at 13:49
source share
β€” -

Not subclasses of QThread for Qt 4.4+

Although Aiua's answer is good, I want to point out some issues with QThread and Qt 4.6 or 4.7.

This article summarizes: http://blog.qt.io/blog/2010/06/17/youre-doing-it-wrong/

Lack of Qt documentation

Unfortunately, the problem is related to the lack of documentation updates. Prior to Qt 4.4, QThread did not implement the default implementation (), which meant that you had to subclass QThread to use it.

If you are using Qt 4.6 or 4.7, you almost certainly should not subclass QThread.

Use moveToThread

The key to getting slots to execute in a workflow is to use the moveToThread method, as Aiua pointed out.

+35
Dec 02 '11 at 17:24
source share

you must signal to run your stream function as

 emit operateCut(examId,examName_examTemplate[examName].studentIdRec,examName_examTemplate[examName].choiceRecA,examName_examTemplate[examName].choiceRecB,examName_examTemplate[examName].objectRecA,examName_examTemplate[examName].objectRecB); 

You can add more than one argument to this signal.

0
Dec 22 '18 at 3:27
source share



All Articles