Why is QThread::finished signal not being emitted?
c++, concurrency, multithreading, qt, qthread
Solution
Signal finished() gets emitted of cause, but you don't catch it.
Here:
connect(_thread, SIGNAL(finished()), this, SLOT(OnFinished()));
`Qt::QueuedConnection` is used, as `_thread` and `this` (service) are in different threads.
By the time `finished()` is emitted, `_thread`'s event loop already finished executing, so signal will not be delivered to the slot.
You can explicitly use `Qt::DirectConnection`.
EDIT:
QTherad works like this:
QThread::start()
{
emit started();
run();
emit finished();
}
QThread::run()
{
eventloop->exec();
}
So, by the time `finished` is emitted, eventloop already stop execution. And as you move `service` to `_thread`, service's event loop is `_thread` event loop.
Note, that `QObject` itself has no its own event loop. Event loops are created by dialogs, threads and application.
Actually I will recommend in your simple case just use `QtConcurent::run`, as you do not perform actual event processing in the new thread, but just run single function.
Problem
I've created my own `TestService` which runs on a separate `QThread`, but when the `MainLoop` terminates the `QThread::finished` signal does not get emitted. I saw a similar question, but the problem was slightly different there because the OP was overloading `QThread` whereas I simply move my class to the thread. Note that I do not overload the `QThread` class, I only overload `QObject` based on this example: http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/ Here is my `TestService` class: ``` #include <QObject> #include <QThread> #include <QMutex> #include <QWaitCondition> #include <iostream> using namespace std; class TestService: public QObject { Q_OBJECT; private: volatile int _count; QWaitCondition _monitor; QMutex _mutex; QThread* _thread; public: TestService(int numSeconds) { _count = numSeconds; _thread = NULL; cout << "TestService()" << endl; } virtual ~TestService() { cout << "~TestService()" << endl; } void Start() { QMutexLocker locker(&_mutex); if(_thread == NULL) { _thread = new QThread; // Move this service to a new thread this->moveToThread(_thread); // The main loop will be executed when the thread // signals that it has started. connect(_thread, SIGNAL(started()), this, SLOT(MainLoop())); // Make sure that we notify ourselves when the thread // is finished in order to correctly clean-up the thread. connect(_thread, SIGNAL(finished()), this, SLOT(OnFinished())); // The thread will quit when the sercives // signals that it's finished. connect(this, SIGNAL(Finished()), _thread, SLOT(quit())); // The thread will be scheduled for deletion when the // service signals that it's finished connect(this, SIGNAL(Finished()), _thread, SLOT(deleteLater())); // Start the thread _thread->start(); } } void Stop() { _count = 0; _monitor.wakeAll(); } private slots: void MainLoop() { cout << "MainLoop() Entered" << endl; while(_count > 0) { cout << "T minus " << _count << " seconds." << endl; QMutexLocker locker(&_mutex); _monitor.wait(&_mutex, 1000); _count--; } cout << "MainLoop() Finished" << endl; emit Finished(); } virtual void OnFinished() { cout << "OnFinished()" << endl; } signals: void Finished(); }; ``` Here is the testing code: ``` void ServiceTest() { cout << "Press q to quit." << endl; cout << "Press s to start." << endl; cout << "Press t to stop." << endl; QSharedPointer<TestService> testService(new TestService(10)); char in = 'a'; while( in != 'q' ) { switch(tolower(in)) { case 's': testService->Start(); break; case 't': testService->Stop(); break; default: break; } cin.get(in); in = tolower(in); } } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); ServiceTest(); QTimer::singleShot(0, &a, SLOT(quit())); return a.exec(); } ``` The output is: ``` Press q to quit. Press s to start. Press t to stop. TestService() s MainLoop() Entered T minus 10 seconds. T minus 9 seconds. T minus 8 seconds. t MainLoop() Finished q ~TestService() Press any key to continue . . . ``` Could anybody explain why is `finished` not being emitted how I can fix it?