Qt Call Slot Thread
Last time I explained how plain C++ objects and their methods interact with threads. This time around, we will look at QObjects
, and their “thread affinity”.
- This is rather intuitive and easy to used. But when SLOTS and Qt event loop are used in the worker thread, some users do it wrong. Hughes, one of the Qt core developers, recommend that use worker objects by moving them to the thread using QObject::moveToThread. Unfortunately, some users went on a crusade against the former usage.
- The main thing in this example to keep in mind when using a QThread is that it's not a thread. It's a wrapper around a thread object. This wrapper provides the signals, slots and methods to easily use the thread object within a Qt project. To use it, prepare a QObject subclass with all your desired functionality in it.
Qt provides some new features for multithreading such as signal / slot, event loop in each thread, As we have already known in Qt, each program has one thread when it is started. This thread is called the main thread or GUI thread in Qt applications.
Now that we know object methods can be accessed by any thread at any time,we’ll consider the situation from the point of view of Qt.
What are QObjects?
Qt is a great framework, and at its heart areQObjects
.Through Qt’s moc compilerextra functionality is seemlessly added to C++ objects.The two most notable additions are signals and slots for inter-object communication, and events.These allow great flexibility and modularity, but how do they work in the context of threads?
For example, if an event or slot is triggered in a QObject
(whichultimately triggers a function), which thread is calling that function? Theanswer lies in thread affinity. But let’s back up a bit.
Qt threads and Event loops
Having the ability to asynchronously trigger functions, and raise/handle eventsmeans that Qt must have some kind of an event loop. An event loop will continuallymonitor a queue of events to be handled, and dispatch them accordingly.Indeed, every QThread
has a built-in event loop that can be entered.
One way to see this directly is by inheriting from QThread
:
The above is a good example for demonstration, but is rarely done in production. We will see a better way to run custom code on QThreads in the next section.
In particular the GUI thread (the main thread), also has an event loop which islaunched by calling QApplication::exec()
, which only returns after the user has quit the program.
So far the most important thing to remember is:
Threads in Qt handle asynchronous events, and thus all have an event-loop.
QObjects and QThreads
Now we come to the meat of this post- if C++ objects can be accessed by anythread, then what thread is handling the events of a particular QObject
?The answer is that whenever a QObject
is created, it is assigned a parent threadwhich handles all of it’s events and slot invocations- it has a threadaffinity. Whichever thread it was created in, becomes it’s parent thread!
This is where the confusion came about for me. On the one hand C++ objectmethods can be called from any thread at any time, while QObjects
(themselvesC++ objects) have a parent thread which handles its events. As you can hopefullysee, there is no conflict:
QObject methods can be called from any thread at any time, just like a C++object. In addition, a parent thread is assigned to handle anyasynchronous events and slot invocations.
So there are two ways for a function to be called on a QObject:
- Directly from any thread
- Indirectly by invoking a connected slot or raising an event. This posts an event onto the parent thread’s event loop, which eventually calls the function in question.
To complete this article, let’s look at running our code on other threads.As promised before we will not inherit from QThread
for the job.If we can’t customize a thread, and QObjects
are bound to the thread that created them, how can we achieve this? Qt allows users to moveQObjects
to other threads, thereby changing the thread affinity to the new thread:
This is much simpler and easier to follow than subclassing a QThread each time you want to create a worker thread.Thanks to Jurily for suggesting this in a reddit comment.
I hope you enjoyed this simplified rundown of QObjects
and threads! More in-depth documentation can be found on the Qt-project website.
When I work with multithreading in Qt at the first time, I feel it really confused with the concepts Signal/Slot. I always have some error about that it can not create threads in QtNetworkManager thread.
So, in this article, we will discuss about multithreadin in Qt. To go through this article, we will look forward you can easily grasp all of things about multithreading in Qt.
Table of contents
- Introduction to Multithreading in Qt
Qt Call Slot Thread Holders
Introduction to Multithreading in Qt
In Qt, it has own cross-platform implementation of threading. The structure about multithreading in Qt is not as same as multithreading in C++. Qt provides some new features for multithreading such as signal / slot, event loop in each thread, …
As we have already known in Qt, each program has one thread when it is started. This thread is called the main thread
or GUI thread
in Qt applications. The Qt GUI must run in this thread. All widgets and several related classes, for example QPixmap
, do not work in secondary threads. A secondary thread is commonly referred to as a worker thread because it is used to offload processing work from the main thread.
There are basically two use cases for threads:
- Make processing faster by making use of multicore processors.
- Keep the GUI thread or other time critical threads responsive by offloading long lasting processing or blocking calls to other threads.
The QThread
is the central class of the Qt threading system to run code in a different thread.
It’s a QObject
subclass.
- Not copiable / moveable.
- Has signals to nofify when the thread starts / finishes.
It is meant to manage a thread.
A QThread
instance manages one thread of execution within the program.
So, to understand all of knowledge about multithreading, we have to really try hard to completely digest them.
How to use multithread in Qt
Some below steps will be used to create thread in Qt:
- To create a new thread executing some code, subclass
QThread
and reimplementrun()
method. - Then, create an instance of the subclass and call
start()
. - Threads have priorities that we can specify as an optional parameter to
start()
, or change withsetPriority()
.
For example:
Some notes in QThread usage:
- The thread will stop running when (some time after) returning from
run()
. QThread::isRunning()
andQThread::isFinished()
provide information about the execution of the thread.- We can also connect to the
QThread::started()
andQThread::sleep()
functions. Generally, it is a bad idea, being event driven (or polling) is much better. - We can wait for a
QThread
to finish by callingwait()
on it. Optionally, passing a maximum number of milliseconds to wait. - Be sure to always destroy all the QObjects living in secondary threads before destroying the corresponding QThread object.
- Do not ever block the GUI thread.
From a non-main thread, we cannot:
- Perform any GUI operation
- Including, but not limited to: using any
QWidget
/Qt Quick
/QPixmap
APIs. - Using
QImage
,QPainter
is OK. - Using OpenGL may be OK: check at runtime
QOpenGLContext::supportsThreadedOpenGL()
.
- Including, but not limited to: using any
- Call
Q(Core Gui)Application::exec()
.
Qt Call Slot Thread Tool
Ensuring destruction to QObjects:
- Create them on QThread::run() stack.
- Connect their QObject::deleteLater() slot to the QThread::finished() signal.
- Move them out of the thread.
For example:
There are two basic strategies of running code in a separate thread with QThread:
Without an event loop
- Subclass QThread and override QThread::run()
Create an instance and start the new thread via QThread::start().
For example:
With an event loop
- An event loop is necessary when dealing with timers, networking, queued connections, and so on.
Qt supports per-thread event loops
Each thread-local event loop delivers events for the QObjects living in that thread.
For example:
We can start a thread-local event loop by calling QThread::exec() from within run():
QThread::quit()
or QThread::exit() will quit the event loop.We can also use QEventLoop or manual calls to QCoreApplication::processEvents().
Qt Call Slot In Different Thread
When to use alternatives to Threads
##
Passing argument to a SLOT
First way: use
QSignalMapper
class.It’s worth noting that in Qt5, C++11,
QSignalMapper
is deprecated. From the link: “This class is obsolete. It is provided to keep old source code working. We strongly advise against using it in new code.”Second way: With Qt5 and a C++11 compiler, the idiomatic way to do such things is to give a functor to
connect
:The third argument to
connect
is nominally optional. It is used to set up the thread context in which the functor will execute. It is always necessary when the functor uses aQObject
instance. If the functor uses multipleQObject
instances, they should have some common parent that manages their lifetime and the functor should refer to that parent, or it should be ensured that the objects will outlive the functor.On Windows, this works in MSVC2012 & newer.
Note: If we replace
&QAction::triggered
bySIGNAL(triggered(bool))
, and something looks like the below:The compiler will send an error, and the error message will tell us why: there’s no QObject::connect overload that takes a const char * as the 2nd argument and a functor as the third or fourth argument. The Qt4-style connect syntax doesn’t mix with the new syntax. If you wish to use the old syntax, you forfeit the ease of connecting to functors (even though it could be approximated if you had a C++11 compiler but used Qt4).
Third way: use
QObject::sender()
in the slot.
How to call Slot in a thread from different thread
Assuming that we have first thread - OurThread
class, second thread - AdditionalThread
, and slot in OurObject
class, then, OurObject
will be passed to the AdditionalThread
class.
Our problem is that we have to emit a signal from OurThread
, and slot in OurObject
will be called.
Source code:
In
OurThread
classIn
AdditionalThread
classIn OurObject class
In
main
function
Wrapping up
- Do not subclass QThread. That’s the starting point for many programmers’ headaches. A QThread is a thread manager, which controls one thread. A QThread is not a thread. Transfer information from thread to thread via signals and slots, using an event-driven approach.
Thanks for your reading.
Refer: