Why is QThread::finished signal not being emitted?
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.
Kiril
CEO and Co-Founder of ST6.io E-mail: click to reveal e-mail
Updated on June 04, 2022Comments
-
Kiril almost 2 years
I've created my own
TestService
which runs on a separateQThread
, but when theMainLoop
terminates theQThread::finished
signal does not get emitted. I saw a similar question, but the problem was slightly different there because the OP was overloadingQThread
whereas I simply move my class to the thread.Note that I do not overload the
QThread
class, I only overloadQObject
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?