Qt Slot Thread
2021年5月3日Register here: http://gg.gg/ugstm
*Qt Slot Threaded
*Qt Slot Thread Dimensions
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.Qt Slot Threaded
I have submitted a patch to the documentationto not discourage sub-classing QThread anymore.
The QThreadclass provides a platform-independent way to manage threads. A QThreadobject manages one thread of control within the program. QThreads begin executing in run. By default, run starts the event loop by calling exec and runs a Qt event loop inside the thread. However, the connected slot function Syncro::jumpToFrame(int newframe) does not get called. If I change the connect from QueuedConnection to DirectConnection the slot function gets called but, as expected, in the context of my serviceThread. I need the slot function to run on the main thread. How Qt Signals and Slots Work - Part 3 - Queued and Inter Thread Connections. The thread that delivers the event will release the semaphore right after the slot has been called. Meanwhile, the thread that called the signal will acquire the semaphore in order to wait until the event is processed. The thread that delivers the event will release the semaphore right after the slot has been called. Meanwhile, the thread that called the signal will acquire the semaphore in order to wait until the event is processed. A long running operation has to be put in another thread. During the course of processing, status information should be sent to the GUI thread. Use QThread, reimplement run and emit signals as needed. Connect the signals to the GUI thread’s slots using queued signal/slot connections. Slots of vegas mobile lobby. One call: Operations are to be performed on all items of a.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::threadand 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).
There are basically two different ways of using QThread directly: Worker threads or subclassing. Those two are confusing to a lot of developers, and I will try to explain when you should use those. I will also explain how signals and slots work with threads and how they can help you or lead to problems.
There are other ways to use QThread than those two. There are hybrid cases that lie somewhere between the two general classes, and you can use QThreadPool or the QtConcurrent. Those cases will not be described here, but I might come back to those in later blog posts.
When you look at the discussion on whether or not to subclass QThread, you will find a lot of people who claim this is bad. For example the famous “You’re doing it wrong” blog post from 2010 (yes, this is an old discussion). I have mixed feelings about this blog post and the arguments it presents. On one hand, I actually encourage developers to follow the recommendations in this article, because I agree that this is the path that leads to fewer errors in your code. OTOH, there are certainly valid use cases for subclassing.
The fundamental problem here is that most developers do not really understand the thread model of Qt. And in some cases they do not even understand threading at all. There are a lot of developers in this industry who should not touch multithreaded code at all, but still have tasks in their daily job that force them to do this. I won’t try to educate general thread development here, but I will encourage everyone who needs to learn this to read a good book on multithreaded development. I’m only going to talk about the QThread class here and assume you understand threading.
So let’s get started on the issue at hand.
There are two Qt technologies that you need to understand before you can understand why QThread works the way it does.QObject thread affinity
The first of those two technologies is thread affinity. Each QObject has a thread that it belongs to. Unless you set this manually, QObject chooses the current thread when the constructor is run.
Thread affinity has a bunch of subtle consequences for our objects, once you start going multithreaded. Of course, if you don’t have any threads, the objects all live in the main thread, and then you don’t have to worry about it. But with threading, you do have to worry about it.
The first thing you have to know is what this means for signals and slots.
When you do a connect from a signal to a slot, you have a choice of connection type. Those can be automatic, direct or queued. Yes, there are a couple of others, but those are not interesting from a threading point of view.
With a direct connection, the slot will be called by the current thread that is emitting the signal. Usually, this is very bad, if the two objects live in different threads. There are cases where you can do this – one example could be a slot that locks a mutex, adds something to a queue, unlocks and returns. But you have a problem if the object can be deleted by another thread while your slot is being executed, of course. My recommendation is not to use this unless you absolutely have to, you really know what you are doing, and make sure you document both sides very precisely.
For queued connections to work, the thread where the receiving object lives (i.e. has the thread affinity), must have an active event loop. This is not necessary for the sender. What happens is that the sending signal will create an event with the arguments of the signal and send this event to the receiver thread eventloop. In the eventloop, the event is transformed to a normal slot call. This happens no matter if the two objects live in the same thread or if they are in different threads. (And this is one of the simplest ways to send information from one thread to another.)
Automatic connection does a check in the signal whether the thread affinity of the receiver is the same as the current thread. If these are the same, it does a direct signal to slot call. If they are different, this is handled as a queued connection. This check is done every time the signal is emitted, which means the thread of the signal is irrelevant and the connect just works. Note that the signalling object does not have to live in a thread with an event loop.QThread thread affinity
The second thing you need to understand, is the thread affinity of the QThread object. This is the part that confuses a lot of developers, although the rules are actually quite simple.
The thread affinity of a QThread object is the creating thread. It does not live in the thread that it models and implements. This may sound counterintuitive, until you actually think about this.
First, when you create the QThread object, the new thread doesn’t exist. This means the constructor will necessarily have to run in the thread that creates it. Also, when the thread is finished and you want to delete it, this will be done in the creating thread as well, so the destructor runs in the creating thread.
However, in the run method of QThread, you are now in the new thread.
This means when you create objects in a QThread subclass method, they will have different thread affinity based on the instantiation time. If you create an object in the constructor (or in the destructor, but that’s rare) this object will have the calling thread affinity. If you create an object in the run method, this will have the new thread affinity. If you have a method on the QThread subclass, an object created in here will (as usual) have the current thread affinity – so if you call it from the constructor it will have the creating thread affinity, and if you call it from run it will have the new thread affinity.
For signals, the thread affinity doesn’t matter. But for slots it matters a lot.Subclassing QThread
Now you can perhaps appreciate why subclassing QThread can be a problem. If you have anything using slots in the subclass objects, the thread affinity will mean that it will use the original thread. This is also the case for lambda slots or what other tricks you could come up with.
So, to “fix” this, developers try various workarounds. First, they use moveToThread(this) on the thread object. Unfortunately, this is probably the worst thing you can do, because that is a violation of the basic assumption of QThread itself. Others will connect using the DirectConnection flag, which actually works, but is a very brittle solution that probably will break while people are working on the code in the years to come.
The next problem you have to consider is when you instantiate other objects from the thread object itself. If you want an object to live in the new thread, you must instantiate it inside the run method and not set the thread object as the parent, because Qt does not like the parent-child relationship to go across from one thread to another.RecommendationsQt Slot Thread Dimensions
So, now we’re finally ready for a list of what you should do in different cases.
If you have a task you need to run in a QThread, this is the place where you do as the QThread documentation says, and create a worker thread. Just instantiate a QThread object, instantiate the objects to live in this thread, call moveToThread(thread) on those objects and start the thread. This is what you should do for most cases.
If you have something that’s just a pure calculation or something that connects to hardware, then you will often use a QThread subclass. Yes, you can implement this using worker threads as well, but that’s usually a silly way to do it. (For the pure calculation case, I would actually use QtConcurrent or the QThreadPool, but that’s a topic for a later blog post.)
When you look at this recommendation, there are two things that are the defining questions:
*Do you need slots?
*Do you need QObject instances in the new thread?
If the answer to one of those questions is yes, then you should follow the standard recommendation and use a worker thread. If the answer is no, you have a choice between subclassing and worker threads.
If you answer yes to either of those questions and still choose subclassing, you are probably going to have issues that are really hard to find. Remember, there’s actually a reason people suggest that you don’t subclass QThread. If you do it, you expose yourself to a couple of sets of problems that you don’t have when you use a worker thread.
Register here: http://gg.gg/ugstm
https://diarynote.indered.space
*Qt Slot Threaded
*Qt Slot Thread Dimensions
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.Qt Slot Threaded
I have submitted a patch to the documentationto not discourage sub-classing QThread anymore.
The QThreadclass provides a platform-independent way to manage threads. A QThreadobject manages one thread of control within the program. QThreads begin executing in run. By default, run starts the event loop by calling exec and runs a Qt event loop inside the thread. However, the connected slot function Syncro::jumpToFrame(int newframe) does not get called. If I change the connect from QueuedConnection to DirectConnection the slot function gets called but, as expected, in the context of my serviceThread. I need the slot function to run on the main thread. How Qt Signals and Slots Work - Part 3 - Queued and Inter Thread Connections. The thread that delivers the event will release the semaphore right after the slot has been called. Meanwhile, the thread that called the signal will acquire the semaphore in order to wait until the event is processed. The thread that delivers the event will release the semaphore right after the slot has been called. Meanwhile, the thread that called the signal will acquire the semaphore in order to wait until the event is processed. A long running operation has to be put in another thread. During the course of processing, status information should be sent to the GUI thread. Use QThread, reimplement run and emit signals as needed. Connect the signals to the GUI thread’s slots using queued signal/slot connections. Slots of vegas mobile lobby. One call: Operations are to be performed on all items of a.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::threadand 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).
There are basically two different ways of using QThread directly: Worker threads or subclassing. Those two are confusing to a lot of developers, and I will try to explain when you should use those. I will also explain how signals and slots work with threads and how they can help you or lead to problems.
There are other ways to use QThread than those two. There are hybrid cases that lie somewhere between the two general classes, and you can use QThreadPool or the QtConcurrent. Those cases will not be described here, but I might come back to those in later blog posts.
When you look at the discussion on whether or not to subclass QThread, you will find a lot of people who claim this is bad. For example the famous “You’re doing it wrong” blog post from 2010 (yes, this is an old discussion). I have mixed feelings about this blog post and the arguments it presents. On one hand, I actually encourage developers to follow the recommendations in this article, because I agree that this is the path that leads to fewer errors in your code. OTOH, there are certainly valid use cases for subclassing.
The fundamental problem here is that most developers do not really understand the thread model of Qt. And in some cases they do not even understand threading at all. There are a lot of developers in this industry who should not touch multithreaded code at all, but still have tasks in their daily job that force them to do this. I won’t try to educate general thread development here, but I will encourage everyone who needs to learn this to read a good book on multithreaded development. I’m only going to talk about the QThread class here and assume you understand threading.
So let’s get started on the issue at hand.
There are two Qt technologies that you need to understand before you can understand why QThread works the way it does.QObject thread affinity
The first of those two technologies is thread affinity. Each QObject has a thread that it belongs to. Unless you set this manually, QObject chooses the current thread when the constructor is run.
Thread affinity has a bunch of subtle consequences for our objects, once you start going multithreaded. Of course, if you don’t have any threads, the objects all live in the main thread, and then you don’t have to worry about it. But with threading, you do have to worry about it.
The first thing you have to know is what this means for signals and slots.
When you do a connect from a signal to a slot, you have a choice of connection type. Those can be automatic, direct or queued. Yes, there are a couple of others, but those are not interesting from a threading point of view.
With a direct connection, the slot will be called by the current thread that is emitting the signal. Usually, this is very bad, if the two objects live in different threads. There are cases where you can do this – one example could be a slot that locks a mutex, adds something to a queue, unlocks and returns. But you have a problem if the object can be deleted by another thread while your slot is being executed, of course. My recommendation is not to use this unless you absolutely have to, you really know what you are doing, and make sure you document both sides very precisely.
For queued connections to work, the thread where the receiving object lives (i.e. has the thread affinity), must have an active event loop. This is not necessary for the sender. What happens is that the sending signal will create an event with the arguments of the signal and send this event to the receiver thread eventloop. In the eventloop, the event is transformed to a normal slot call. This happens no matter if the two objects live in the same thread or if they are in different threads. (And this is one of the simplest ways to send information from one thread to another.)
Automatic connection does a check in the signal whether the thread affinity of the receiver is the same as the current thread. If these are the same, it does a direct signal to slot call. If they are different, this is handled as a queued connection. This check is done every time the signal is emitted, which means the thread of the signal is irrelevant and the connect just works. Note that the signalling object does not have to live in a thread with an event loop.QThread thread affinity
The second thing you need to understand, is the thread affinity of the QThread object. This is the part that confuses a lot of developers, although the rules are actually quite simple.
The thread affinity of a QThread object is the creating thread. It does not live in the thread that it models and implements. This may sound counterintuitive, until you actually think about this.
First, when you create the QThread object, the new thread doesn’t exist. This means the constructor will necessarily have to run in the thread that creates it. Also, when the thread is finished and you want to delete it, this will be done in the creating thread as well, so the destructor runs in the creating thread.
However, in the run method of QThread, you are now in the new thread.
This means when you create objects in a QThread subclass method, they will have different thread affinity based on the instantiation time. If you create an object in the constructor (or in the destructor, but that’s rare) this object will have the calling thread affinity. If you create an object in the run method, this will have the new thread affinity. If you have a method on the QThread subclass, an object created in here will (as usual) have the current thread affinity – so if you call it from the constructor it will have the creating thread affinity, and if you call it from run it will have the new thread affinity.
For signals, the thread affinity doesn’t matter. But for slots it matters a lot.Subclassing QThread
Now you can perhaps appreciate why subclassing QThread can be a problem. If you have anything using slots in the subclass objects, the thread affinity will mean that it will use the original thread. This is also the case for lambda slots or what other tricks you could come up with.
So, to “fix” this, developers try various workarounds. First, they use moveToThread(this) on the thread object. Unfortunately, this is probably the worst thing you can do, because that is a violation of the basic assumption of QThread itself. Others will connect using the DirectConnection flag, which actually works, but is a very brittle solution that probably will break while people are working on the code in the years to come.
The next problem you have to consider is when you instantiate other objects from the thread object itself. If you want an object to live in the new thread, you must instantiate it inside the run method and not set the thread object as the parent, because Qt does not like the parent-child relationship to go across from one thread to another.RecommendationsQt Slot Thread Dimensions
So, now we’re finally ready for a list of what you should do in different cases.
If you have a task you need to run in a QThread, this is the place where you do as the QThread documentation says, and create a worker thread. Just instantiate a QThread object, instantiate the objects to live in this thread, call moveToThread(thread) on those objects and start the thread. This is what you should do for most cases.
If you have something that’s just a pure calculation or something that connects to hardware, then you will often use a QThread subclass. Yes, you can implement this using worker threads as well, but that’s usually a silly way to do it. (For the pure calculation case, I would actually use QtConcurrent or the QThreadPool, but that’s a topic for a later blog post.)
When you look at this recommendation, there are two things that are the defining questions:
*Do you need slots?
*Do you need QObject instances in the new thread?
If the answer to one of those questions is yes, then you should follow the standard recommendation and use a worker thread. If the answer is no, you have a choice between subclassing and worker threads.
If you answer yes to either of those questions and still choose subclassing, you are probably going to have issues that are really hard to find. Remember, there’s actually a reason people suggest that you don’t subclass QThread. If you do it, you expose yourself to a couple of sets of problems that you don’t have when you use a worker thread.
Register here: http://gg.gg/ugstm
https://diarynote.indered.space
コメント