Let\'s say I call QtConcurrent::run()
which runs a function in a worker thread, and in that function I dynamically allocate several QObjects (for later use). Since
However, once the worker thread terminates, the QObject thread affinity should no longer be valid.
The worker thread does NOT terminate after your function call. The whole point of using QtConcurrent::run is executing a large number of small tasks on the global thread pool (or some provided QThreadPool
) while re-using threads to avoid the overhead of creating and destroying threads for each one of these small tasks. In addition to distributing computation across all available cores.
You can try looking at the source code for Qt to see how QtConcurrent::run is implemented. You will see that it ends up calling RunFunctionTaskBase::start, which essentially calls QThreadPool::start with a QRunnable
that calls the function that was passed initially to QtConcurrent::run
.
Now the point that I want to get to is that, QThreadPool::start
is implemented by adding the QRunnable
to a queue, and then trying to wake up one of the threads from the thread pool (which are waiting for a new QRunnable
to be added to the queue). The thing to note here, is that threads from the thread pool are not running an event loop (they are not designed to act this way), they are there just to execute QRunnable
s in the queue and nothing more (they are implemented this way for performance reasons obviously).
This means that, the moment you are creating a QObject
in a function executed in QtConcurrent::run
, you are just creating a QObject
that lives in a thread with no event-loop, from the docs, restrictions include:
If no event loop is running, events won't be delivered to the object. For example, if you create a
QTimer
object in a thread but never callexec()
, theQTimer
will never emit itstimeout()
signal. CallingdeleteLater()
won't work either. (These restrictions apply to the main thread as well.)
TL;DR: QtConcurrent::run
runs functions in threads from the global QThreadPool
(or a provided one). Those threads do not run an event loop, They just wait for QRunnable
s to run. So, a QObject
living in a thread from these threads doesn't get any events delivered.
In the documentation, They have put using QThread (possibly, with an event loop and a worker object) and using QtConcurrent::run as two separate multi-threading technologies. They are not meant to be mixed together. So, no worker objects in thread pools, this is just asking for trouble.
The question: Does Qt automatically move the QObjects into the parent thread, or are we responsible in moving them to a valid thread before the worker thread terminates?
I think that after looking at things this way, The answer is obvious that Qt does NOT move QObject
s into any thread automatically. The documentation has warned about using a QObject
in a QThread
without an event loop, and that's it.
You are free to move them to whatever thread you like. But please keep in mind that moveToThread() can sometimes cause problems. For example, if moving your worker object involves moving a QTimer
:
Note that all active timers for the object will be reset. The timers are first stopped in the current thread and restarted (with the same interval) in the targetThread. As a result, constantly moving an object between threads can postpone timer events indefinitely.
Conclusion: I think that you should consider using your own QThread
that runs its event loop, and create your worker QObject
s there instead of using QtConcurrent
. This way is far better than moving QObject
s around, and can avoid many errors that can arise from using your current approach. Have a look at the comparison table of multi-threading technologies in Qt and choose the technology that best suits your use case. Only use QtConcurrent
if you want to just execute a one-call function and get its return value. If you want permanent interaction with the thread, you should switch to using your own QThread
with worker QObject
s.