Qthread Slot Quit
This would be done by posting a suspend request into the queue and waiting until it is handled. Pretty much similar to QThread::quit + wait. Resume would signal the wait condition to wake the sleeping thread up to continue its execution. Let’s review the interface and implementation. Qt/C - Lesson 048. QThread — How to work with threads using moveToThread. In a previous article we are only a little touch to working with threads, and in the version that is more for the customization of thread, although it can be used to perform o. When processed, that event will call the slot the same way we call them for direct connections. All the information (slot to call, parameter values.) are stored inside the event. Copying the parameters. The argv coming from the signal is an array of pointers to the arguments. The problem is that these pointers point to the stack of the. slot void QThread:: quit Tells the thread's event loop to exit with return code 0 (success). Equivalent to calling QThread::exit(0). This function does nothing if the thread does not have an event loop. See also exit and QEventLoop. Void QThread:: requestInterruption Request the interruption of the thread.
This post is about the use of QThread. It is an answer to a three years old blog post by Brad, my colleague at the time:You're doing it wrong
In his blog post,Brad explains that he saw many users misusing QThread by sub-classing it, adding someslots to that subclass and doing something like this in the constructor:
They move a thread to itself. As Brad mentions, it is wrong: the QThread is supposed tobe the interface to manage the thread. So it is supposed to be used from the creating thread.
Slots in the QThread object are then not run in that thread and having slots in a subclass of QThreadis a bad practice.
But then Brad continues and discourages any sub-classing of QThread at all.He claims it is against proper object-oriented design.This is where I disagree. Putting code in run()
is a valid object-oriented way to extend a QThread:A QThread represents a thread that just starts an event loop, a subclass represents a threadthat is extended to do what's in run()
.
After Brad's post, some members of the community went on a crusade against sub-classing QThread.The problem is that there are many perfectly valid reasons to subclass QThread.
With Qt 5.0 and Qt 4.8.4, the documentation of QThread was changed so the sample code does not involvesub-classing.Look at the first code sampleof the Qt 4.8 QThread documentation (Update: link to archive.org since the newer documentation is fixed).It has many lines of boiler plate just to run some code in a thread. And the there is evena leak: the QThread is never going to quit and be destroyed.
I was asked on IRC a question from an user who followed that example in orderto run some simple code in a thread. He had a hard time to figure out how to properlydestroy the thread. That is what motivated me to write this blog entry.
If you allow to subclass QThread, this is what you got:
This code does no longer leak and is much simpler and has lessoverhead as it does not create useless object.
The Qt threading examplethreadedfortuneserveris an example that uses this pattern to run blocking operations and is much simpler thanthe equivalent using a worker object.
I have submitted a patch to the documentationto not discourage sub-classing QThread anymore.
Rules of thumbs
When to subclass and when not to?
- If you do not really need an event loop in the thread, you should subclass.
- If you need an event loop and handle signals and slots within the thread, you may not need to subclass.
What about using QtConcurrent instead?
QThread is a quite low level and you should better use a higher levelAPI such as QtConcurrent.
Now, QtConcurrent has its own set of problems: It is tied to a single thread pool so it is nota good solution if you want to run blocking operations. It has also some problems in itsimplementation that gives some performance overhead. All of this is fixable.Perhaps even Qt 5.1 will see some improvements.
A good alternative is also the C++11 standard library withstd::thread
and std::async
which arenow the standard way to run code in a thread. And the good news is that it still works fine with Qt:All other Qt threading primitives can be used with native threads.(Qt will create automatically create a QThread if required).
Effective Threading Using Qt
Over the years using Qt I’ve seen a lot of difficulty using threads with Qt.Threads can be difficult and Qt provides a lot of ways to make threads easy towork with. Still basic / direct / low level threading (I’ll just call thisbasic) is often seen as difficult with Qt. It really isn’t though.
There are three main ways I’ve seen people handle basic threading in their Qtapplications. The first is using system threads, either pthread or Windowsthreads. I don’t like this approach because you’re basically writing a portablethread library. You can use an already built portable thread library but whyuse a non-Qt solution when Qt already provides portable threading.
The two other approaches are defined by Qt’s QThreaddocumentation. 1) use a QObject worker. 2)subclass QThread and reimplement the run function.
I like using a QObject worker and I think this is the best (and easiest)approach. That said, I don’t like how Qt’s documentation explains this. It usestwo QObject classes to handle this. A variation of this approach is what I’mgoing to demonstrate.
The other documented approach is subclassing QThread. This isn’t a horribleidea but I don’t think it’s the cleanest approach. It also ties thefunctionality to a thread making code reuse low in this case. You could getaround this limitation by putting the functionality in a separate class but nowyou have two classes and the thread subclass really isn’t necessary when usingthe QObject worker approach.
This is a very simple example that demonstrates two types of workers. One takesarguments and runs until it’s task is finished. The second on runs until it’stold to stop. The second worker could take arguments if you need it to. Forthis example the workers both just increment a count every second and send theresult to a QMainWindow
for it to be displayed.
Here is all the code that goes into the example which will have the main partsexplained after:
main.cpp
mainwindow.h
mainwindow.cpp
mainwindow.ui
countworker.h
countworker.cpp
infinitecountworker.h
infinitecountworker.cpp
portablesleep.h
threader.pro
CountWorker
This is a very simple object that increases a count every second. The start andend are set as part of the constructor. Setting up the object using theconstructor makes sense but it’s also because to start the worker we can’t passany arguments. This is a limitation of this method that the worker in Qt’s docsdoes not have. That said, I think it’s fine to use the constructor for argumentpassing. This method doesn’t reuse workers (not a limitation) so it’s fine.Once the worker finishes it’s work is all done and it stops.
InfiniteCountWorker
This worker is very similar to the count worker. It’s to demonstrate infinitetasks unlike CountWorker which demonstrates finite tasks.
The key to his worker is the stopWork slot. Calling this sets sets a flag tolet the worker’s doWork function to exit.
*Workers
Both workers have two signals in common, updateCount
and finished
.UpdateCount
simply sends the current count off. The MainWindow
connects anduses this to, well, update the count. finished signals that the worker is done.This is used to stop the thread and takes care of cleanup. The finished signalcan have multiple overloads. For example to send off a result in addition tosignaling that the worker is finished. You must have a no argument signal forcompletion with this method. You could use a different signal name instead ofoverloading “finished” if you want.
One thing to think about is thread synchronization. Well, with this workermethod you don’t need to worry about it. Initialization of parameters happensbefore the worker is moved to the thread and before the thread is even started.All passing (such as updateCount) happens using signals and slots. When passingdata between threads using signals and slots Qt handles thread synchronizationfor you. The stopWork
function is called via a signal so the function runs onthe thread the work is running on between iterations of the while loop. Sothere is no need to wrap m_running
in a mutex or other synchronizationtechniques.
It might be confusing that I said the stopWork
function happens betweeniterations of the while loop in InfiniteCountWorker. This is because of theqApp->processEvents
call. Without this, the signal to initiate the stopWork
slot won’t be delivered until after the while loop finishes. Which isimpossible in infiniteCountWorker
. Remember the thread is a single thread andeverything running on it is single threaded. The while loop will block anythingelse in the object from running unless you use qApp->processEvents
to allowsignals and slots to process. In the case of the CountWorker
qApp->processEvents
isn’t really necessary since there aren’t any signalsthat are delivered to it. processEvents
is only necessary for signals (fromoutside of or within the thread the worker is running) to initiate slots in theworker. It is not necessary for the worker to send off a signal (likeupdateCount
) to another thread that it’s connected to.
If you haven’t realized by now that with the worker method (my variation orQt’s) the worker has an event loop. Subclassing QThread
only does in somecases (see the documentation for when). You get signals into and out of workerwithout any additional code (except for a single processEvents
call). You getthis essentially for free by using a worker!
MainWindow
The workers aren’t really useful unless they can be started on a thread. That’swhat the MainWindow
in this example is for. The startCount
andstartInfiniteCount
functions are the main thing to look at.
startCount Breakdown
The thread and worker are created on the heap. The worker is initialized heretoo.
Put the worker on the thread so the worker will be run on the thread we createdinstead of the UI thread.
This is how the worker is started when the thread is started.
Connect all the finished signals. When the worker finishes the thread will bestopped with quit()
, the worker will be deleted via deleteLater
. Qt handlesdeletion and takes care of it when safe. This is another advantage of usingQObject
workers. Also, when the worker finishes the countFinished
functionis called so anything in the MainWindow
that needs to happen when the workeris finished is run. Again, you could have a second finished signal (overload)that passes result data back to the MainWindow
. Finally, when the threadfinishes (because of the worker’s finished signal calling the threads quitslot) it will be deleted by deleteLater
. The deleteLater
slots mean wedon’t need to track the the worker or thread pointers and worry about manuallydeleting them.
deleteLater
is very useful. We have finished connected to multiple slots.Deleting a QObject
when there are events pending or within a signal handler(slot) can lead to a crash. deleteLater
ensures that this won’t happen bywaiting until all events are delivered. Also, you can’t delete a QObject
froma thread so this also ensures the UI thread that created the worker and threadis where they are deleted. In this example this isn’t a concern but it’s niceto know that it won’t become one.
Qthread Slot
We don’t need to worry about something like dangling connections because when aQObject
is deleted it automatically disconnects all signals and slots (not inall cases but that will be covered later).
Here the count will be updated on the MainWindow
as it’s incremented in theworker. Again, there is no manual thread synchronization necessary because Qthandles this as part of it’s signal and slot system.
The last line to worry about actually starts the thread which in turns startsthe worker.
startInfiniteCount Breakdown
This function is very similar to startCount
. The only difference is one line.
The MainWindows
button that will stop the InfiniteCountWorker
is connectedto the InfiniteCountWorker
’s stop function.
Qthread Slots
PortableSleep
portablesleep.h is a header only cross platform sleep class. This is how wecreate the one second delay when counting. With Qt5 you can (should) useQThreads
msleep
or sleep
public static functions instead. Qt4 on theother hand defines these functions as protected static functions. So there isno clean way to use them aside from creating a QThread
subclass and exposingthem. Note that this example is not limited to Qt4. This example will runand work with both Qt4 and Qt5. A little bit of thought is all that’s needed toachieve this.
This information isn’t specific to threading but could be very useful to reallyget the most of the worker concept.
This example only uses int. This is a type that can be used with Qt’s signalsand slots as well as many other types such as QString
. There are many complextypes like your own classes or even QMap<QString, QString>>
cannot be usedimmediately with signals and slots.
I say immediately because any class with a public constructor, copy constructorand destructor can be registered with Qt using qRegisterMetaType
. This allowsthe object type to be used with signals and slots. For example you can use thefollowing in the MainWindow
’s constructor to allow a complex type to be used.
The reason we need constructor, copy constructor and destructor is because whennecessary Qt will create a copy of an object and pass the copy to a slot. Inthe case of passing objects between threads using signals and slots a copy willbe passed to the slot. Remember primitive types like int and pointers arealways copies. Complex types may or may not be copies depending on thesituation.Realize that if you are passing a pointer between threads you will need manualsynchronization. If you’re allowing copies to be passed then you don’t need toworry about synchronization.
You’ve probably noticed that in this example the old style SIGNAL
and SLOT
macros were used in the connect functions. This is on purpose because itsupports more compilers. Also, as mentioned, the example code works with bothQt4 (it is still used) and Qt5. I don’t really like new syntax provided byC++11 either. There are too manynegatives for my liking. In thiscase the fact that automatic connection disconnection isn’t support is prettybig. Nor is overloading signals very clean which makes using multiple versionof finish not a friendly. But this is my personal preference and not requiredfor this threading method.
Qthread Slot Quit Smoking
Contrary to popular belief Qt provides very powerful basic threadingcapabilities. I say basic because I didn’t even mention Qt Concurrent whichprovides a lot of high level threading support. Oh and QThread
pool wasn’tmentioned. None of the thread synchronization objects like QMutex
weredescribed either.
Qthread Yieldcurrentthread
Even with all of the threading objects that Qt provides it’s still really easyto use threading with QObject
workers. For most people this is going to beenough for offload some functionality and keep the UI from blocking. While thisis the method I use quite often there are plenty of other ways. I just happento find this to be the cleanest and easiest.