Qthread Emits Finished() Signal But Isrunning() Returns True and Isfinished() Returns False

QThread emits finished() signal but isRunning() returns true and isFinished() returns false

The way the QThread lifecycle works is like this:

  1. You call QThread::start().
  2. At this point, isRunning() should start returning true.
  3. The thread internals start. They emit the started() signal.
  4. The thread internals call run().
  5. Unless you override this in a subclass, run() calls exec().
  6. exec() enters an event loop and stays there until quit() or exit() is called.
  7. exec() and run() return to the internals.
  8. At this point, isFinished() should start returning true and isRunning() false.
  9. The internals emit the finished() signal.
  10. The internals do some final cleanups.
  11. The thread terminates for real.

So you need to call quit() after your location fetcher is done - but this->quit() isn't calling quit() on the thread! This is probably why it's not doing anything.

Your code looks a bit like it was patterned after this article:

http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/

Note how she gives her worker a finished() signal (not the same as QThread::finished) and connects it to the QThread::quit() slot.

QThread.isFinished returns False in slot connected to finished() signal

Turns out it was a bug in qt (https://bugreports.qt-project.org/browse/QTBUG-30251) which is fixed in Qt 4.8.5.
PySide 1.2.1 comes with Qt4.8.5.

QThread finished state

No. The finished state is there to indicate that before that quit() or exit() have been called. It is an alternative to receiving the finished() signal.

The quit() and exit() lead to run() (which is the only part of the thread that actually runs in a separate thread) returning to the thread that your QThread instance belongs to. After that a cleanup procedure is executed - events beside the designated deletion ones can no longer be processed.

The finished state is triggered and you can safely remove the instance of your QThread. finished() signal is emitted (in most cases connected to deleteLater() slots of the objects that reside in the separate thread) and isFinished() returns true.

Naturally if you haven't started the thread it cannot be finished because it never ran. :D Joke aside, it is perfectly safe to remove an instance of QThread that hasn't been started at all.

If you are more interested in this I suggest you look at the source code of QThread to see how the class is sturctured and its implementation works.

Why can a sub-classed QThread simply fail to start?

There is a race condition in the version of Qt I am using. I don't know if it was reported or not before, but I do not have the latest, so it's probably moot unless I can demonstrate it in the current version.

Similar bugs were reported here long ago:

QThread.isFinished returns False in slot connected to finished() signal

(the version I use is much more recent than Qt 4.8.5)

What more important is I can workaround it with the following code

while ( isRunning() )
{
msleep(1);
}
start();

I've run a few tests, and it never seems to take more than 1ms for the race condition to settle. Probably just needs a context switch to clean up.

General QThread understanding: quit() and isRunning()

I can be wrong, but documentation tells us that quit and exit(int ) finishes thread event loop. But exiting thread event loop doesn't mean that thread is finished. You can even run another qthread without even starting event loop by subclassing and reimplementing run method. So calling quit method doesn't mean that thread isFinished() return true. Just connect yourself to finished() signal and do what you wanted with finished thread.

QThread finished() signal is never emited

You have a forever loop:

void StartWork()
{
running = true;
while(running)
{
do work;
}
}

This function will loop, so the event loop of the thread is blocked just after having emitted started(). Thus, finished() cannot be emitted.

Solution 1:

Add the function

void DoWork()
{
if(running)
{
do work
}
}

To Worker, and change

void StartWork()
{
running = true;
}

Then, just connect DoWork to a timer in the thread.

Solution 2:

Change the function

void StartWork()
{
running = true;
while(running)
{
do work;
QCoreApplication::processEvents();
}
}

With this solution, you will have to restart the thread when the worker stops its job (StopWork() will force this function to finish, so the event loop will have no events to handle and the thread will be finished).

QThread won't stop / does not process a signal

I believe the issue is that you actually don't have Qt event loop running in the scenario. If you replace testThread.wait() with a.exec() (which starts the Qt event loop) you should see your signals/slots getting processed properly.

If you want the application to quit when your thread has finished you can use QCoreApplication's quit() slot to do so.

Is it necessary to delete an object if that runs on a QThread if finished signal of QThread is connected to deleteLater?

No it is not necessary. The connection should do exactly what you want as long as the thread does emit finished eventually. See the following Code:

#include <QObject>
#include <QThread>
#include <iostream>

class Test : public QObject {
Q_OBJECT
public:
Test(){
std::cout <<"c'tor" << std::endl;
}
~Test(){
std::cout << "d'tor" << std::endl;
}
};

void startThread(){
QThread* thr = new QThread();
Test* test = new Test();
connect(thr, &QThread::finished, test, &QObject::deleteLater);
test->moveToThread( thr );
thr->start();
thr->quit();
thr->wait();
delete thr;
}

The output is as expected:

c'tor
d'tor

Note that the snippet wont compile right away since its missing a main.

Unable to connect between QThread with finished() signal for multiple Qthread

First of all you should note that the default connection type is Qt::AutoConnection. This means if signal is emitted from a different thread than the receiving object's thread, Qt::QueuedConnection is used. In this case: The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread. So you need an event loop.

It works with 2 threads because you probably have an event loop running in your main thread. In your case where you use only thread2 and thread3 objects, thread2 object will actually live in the main thread, while thread3 object will live in the thread managed by the thread2 object. So slots in thread2 object should work.

But in the case of 3 threads, thread1 object would live in the main thread, thread2 object would live in the thread managed by thread1 object, and because there is no running event loop there, the slot in thread2 object will never be executed.

You can call QThread::exec() in your QThread::run() function, but note that the slots will be executed in the thread where your QThread object lives in, not the thread it manages. Because of this you shouldn't use slots in QThread subclasses. You should create a QObject subclass and move it to a thread.

Another option is to use Qt::DirectConnection for the connection type, when you connect your signals to slots.



Related Topics



Leave a reply



Submit