QRunnable subclass inheriting QObject is wrong?
-
Maybe I am just misunderstanding it so please correct me if I am wrong in my reasoning. This won't be a normal question but a thought rather:
-
Only the QRunnable::run() is executed in another thread. The QRunnable subclass object itself (and all its parts including possibly QObject) are still living in the thread that created them. Nothing is moved and everything stays where it was created with QRunnable and QThreadPool. If you created stuff inside run() however that stuff will live in a thread that executed the function.
-
Added signals & slots from QObject are not asynchronous. While they mimic that behaviour close enough they are send and received in the original thread. They are only triggered from another thread and this works without a problem because the QThreadPool uses a mutex under the hood.
To me this seems like a problem. It achieves its goal (reporting on the job that is being run asynchronously) but scatters resources involved across two threads and only seemingly providing asynchronous signals and slots. And atop of that not being transparent about it at all.
The solution I can think of is actually creating an QObject sub-class object inside QRunnable::run() and connecting there as well (QObject::connect() is fortunately thread safe). That means carrying pointers to senders/receivers with it to the run() context however.
The other solution would be to write your own thread pool class that accounts for the fact that it deals with QObject sub-classes and therefore does proper QObject::moveToThread(). Mere sub-classing the QThreadPool would not imho work but maybe I am wrong here. Anyway I really do wonder why it has not been done this way in the first place because overall in its current form QRunnable provides seemingly nothing that the Qt Concurrent framework does not provide (and that is more transparent and with less code to use). Both were introduced in Qt 4.4 so it does not appear to be some historical reason... but as I mentioned in the beginning I might be misunderstanding it.
-
-
In my opinion QRunnable is sort of a "glue" class, like QFuture or QThread and should not be used for application logic (signals/slots) anyway. I think ideally it should have a run method and nothing else - no members or connections (or as little as possible).
Both QThreadPool and QRunnable are pretty low level classes that belong "below" app logic.So I would bias towards your first suggestion - create the proper "thread bound" object inside the run method and connect to it rather than to the QRunnable subclass.
I'm not sure I like the second idea. Something about a class moving my objects to other threads implicitly that rubs me the wrong way. Not really wrong if documented but it just doesn't "feel right" to me.Another matter is that you can disable the auto-delete feature of QRunnable and run it multiple times, in which case there is no singular thread to move the object to, as it can execute on several at the same time.