Qt documentation states that signals and slots can be direct
, queued
and auto
.
It also stated that if object that owns slot 'lives' in a thread different from object that owns signal, emitting such signal will be like posting message - signal emit will return instantly and slot method will be called in target thread's event loop.
Unfortunately, documentation do not specify that 'lives' stands for and no examples is available. I have 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(); }
Output is:
thread 2 started thread 1 started
MySlot()
is never called :(. What I'm doing wrong?
In Qt, we have an alternative to the callback technique: We use signals and slots. A signal is emitted when a particular event occurs. Qt's widgets have many predefined signals, but we can always subclass widgets to add our own signals to them. A slot is a function that is called in response to a particular signal.
QObject and all of its subclasses are not thread-safe. This includes the entire event delivery system. It is important to keep in mind that the event loop may be delivering events to your QObject subclass while you are accessing the object from another thread.
To use it, prepare a QObject subclass with all your desired functionality in it. Then create a new QThread instance, push the QObject onto it using moveToThread(QThread*) of the QObject instance and call start() on the QThread instance. That's all.
There are quite a few problems with your code :
This code would most likely work (though I have not tested it) and I think it does what you want it to do :
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 I'm not sure on that one, it might be sent from main thread, it doesn't really matter).
No event loop is needed in thread1 since emitting a signal doesn't need an event loop. An event loop is needed in thread2 (lanched by exec()) to receive the signal.
MySlot will be called in thread2.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With