QThread::exit documentation seems wrong
-
QThread::exit manual had this line since forever:
If the eventloop in QThread::exec() is not running then the next call to QThread::exec() will also return immediately.
To me this seems like a direct contradiction to the QThread::quit manual:
This function does nothing if the thread does not have an event loop.
...and here’s the QThread::quit() source code:
void QThread::quit() { exit(); }
I tried an SSCCE which just creates a QThread, calls exit(0) on it, then starts it, and yep, the QThread::exec() does not «return immediately», it starts running just fine.
So, is this a mistake in documentation or am I missing something?
-
I don't see an error here - neither quit() nor exit() will do anything when the thread has no event loop.
-
@ScumCoder The wording could be better, but what I think is meant is something like this:
struct MyThread : public QThread { void run() override { exec(); // This will block until exit() is called exec(); // This will also block until another exit() is called } };
but if you call exit() before exec() the thread object will remember it and the next exec() will pick it up and return immediately, i.e.
struct MyThread : public QThread { void run() override { exec(); // This will block until exit() is called exit(42); // No loop is running here, Thread object "stores" the exit request and code exec(); // This returns immediately with return code 42 } };
So yeah, the the doc is a bit misleading. If event loop is not running it's not true that quit() does nothing. It does something (stores the request and code), but it has no immediately visible result until next exec().
-
Okay, I crawled through the Qt code and here’s what I found.
The exit/quit behavior is governed by two variables:
- quitNow, stored in QThreadData;
- exited, stored in QThreadPrivate.
quitNow is:
- reset to false at the start of QThread::exec
- asserted in exit()
- checked in QEventLoop::exec; if it’s true, exec returns -1
exited is:
- reset to false at the at the start of QThread::start
- assigned to quitNow at the start of QthreadPrivate::start
- asserted in QThread::exit()
- checked at the start of QThread::exec; if it’s true, it’s reset and exec returns
- reset to false at the end of QThread::exec
This leads to a whole rabbit hole of possibilities which makes my head hurt a bit:
- Call exit while QThread isn’t running. No impact on subsequent behavior.
- Call exit while QThread is starting up. Seems like a race condition: if the call squeezes between thread initialization in QThread::start and the start of the actual thread, the very first invocation of exec within the thread will immediately exit.
- Call exit() while QThread is running, no matter whether from within its own run() or from outside. Call exec() within the thread's run(). Exec() returns no matter whether it was called before or after exit(), and returns whatever was passed to exit().
- Call exit() while QThread is running, no matter whether from within its own run() or from outside. Create a QEventLoop within the thread's run(). Call its exec(). QEventLoop::exec() returns no matter whether it was called before or after exit(). If QEventLoop::exec() was called before exit(), it returns whatever was passed to exit(). If QEventLoop::exec() was called after exit(), it returns -1.
One thing is apparent: the documentation is wrong, plain and simple.
-
-
@Christian-Ehrlicher It took me a whole day, but I finally understood that you were referring to the fact that exit()/quit() can't be used in the same vein as requestInterruption()/isInterruptionRequested() or terminate().
I first learned about basic QThread semantics so long ago (more than a decade I think), that the fact that it's possible to not understand that got completely lost on me.