After a lapse of four months after the first, changed a company can log on the blog, record some learning content it
This is to see others write a better article, typesetting a bit messy
How to use Qthread
Origin
Yesterday accidentally saw a Qt Developer (Bradley t.hughes) blog In a piece of article Youare-doing-it-wrong. The result looks dizzy: at least also self-taught for nearly 1 years of Qt, also has been very careful, very carefully read qt and manual and examples and other information, but was suddenly told, Qthread the correct use of the method is a kind of oneself have never seen, and qtmanual , example, a method not mentioned in the book. What's going on...
is manual, exmaple and the information in the introduction are all wrong??
Take a serious look at other people's comments, finally got a little clue. All things originate from the Qthread event loop!
Two ways to use Qthread
1. Do not use event loops. This is one of the official Manual, example and related books that are described in this way.
A. Sub-class Qthread
B. Overloading the run function with a dead loop for a while or for in the run function
C. Set an exit that is marked to control the dead loop.
2. Use the event loop. (blog Youare-doing-it-wrong is a kind of usage in this case.) )
A. Subclasses of Qthread,
B. Overload the run to invoke Qthread::exec ()
C. and define signals and slots for this class, so that because the slot function does not run on the newly opened thread, many people call Movetothread (this) in the constructor to solve the problem
Controversy and confusion are the result of such a statement.
Bradley T. Hughes gives the explanation that Qthread should be considered an interface or control point for an operating system thread, and should not contain code that needs to run in a new thread. The code that needs to be run should be placed in a qobject subclass and then movetothread the object of that subclass into the new thread.
Other than that
Before Qt4.3 (including), run is a virtual function, you must subclass Qthread to implement the run function.
Starting with Qt4.4, Qthreads-no-longer-abstract, run, calls Qthread::exec () by default. This does not require a subclass of Qthread, only the subclass of a qobject is enough, this is the method recommended by Bradley T. Hughes.
Finally understand, but anyway, should be qthread original design caused this problem, and all the documents and examples do not mention how to use qthread further exacerbated the misuse of qthread.
Discussion on the use of Qthread
Qthread seems to be a very difficult thing, especially the signals and slots, there are a lot of people (although users themselves often do not know) in the use of inappropriate (or even wrong) way in using Qthread, casually with Google search, can search out a large number of results. No wonder the Qt developer Bradley T. Hughes to shout you Are-doing-it-wrong.
Like many users, the first time to see this, feel Bradley t.hughes Some inexplicable wonderful, fuss. Despite the discomfort, it was a blog qthread how to use
The past 3 months, although still not how to use thread, but today CSDN forum Someone asked this question, think about it or do my best to tidy it up. Improve yourself, convenience to others, why not?
Qthread things are still more, and I have limited knowledge of the underlying objects, just a little bit to expand (perhaps the most concern of everyone):Qthread in the slots in that thread execution?
Qthread::run
What does the run function do? The manual said clearly:
- Run acts on the thread as the main function for the application. It is the thread's entry, and the start and end of the run means the start and end of the thread.
The original text is as follows (this passage we call the theorem One bar):
- Therun () implementation is for a thread, the main () entry point isfor the application. All code executed in a call stack that startsin the run () function is executed by the new thread, and the threadfinishes W Hen the function returns.
This short text at a glance is finished, but, what does this mean? What can be explained? See section Simple code:
Class Thread:public Qthread {q_object public:thread (qobject* parent=0): Qthread (parent) {} public slots:void slot () {. . } signals:void sig (); Protected:void run () {...}}; int main (int argc, char** argv) {... Thread thread; ... }
In contrast to the previous theorem, the code in the run function is definitely going to run in the secondary thread, what about the other? For example, does the slot run in the secondary or main thread?
You want to say the main thread, but you're unwilling, right?
Qobject::
Connect
When it comes to signal slots , we can't hide from the connect function, but this function is very familiar to everyone. I am embarrassed to use a lot of nonsense to describe it, but do not say no, then compromise, just look at its last parameter (for the sake of simplicity, only see its most commonly used 3 values)
In the following list, we are temporarily called theorem two :
- Automatic connection (auto Connection)
- This is the default setting
- If the signal is emitted within the thread that the receiver is attached to, it is equivalent to a direct connection
- If the thread that emits the signal is different from the thread to which the recipient is attached, it is equivalent to a queue connection
- That is to say, there are only two of the following
- Direct connection (directly Connection)
- When the signal is emitted, the slot function is called directly.
- The slot function executes within the thread that emits the signal, regardless of which thread the slot function belongs to.
- Queue connection (Queued Connection)
- The slot function is called when control returns to the event loop of the thread to which the recipient is attached.
- The slot function executes on the thread attached to the receiver.
Like the previous face, these words can be read by everyone. But what does it mean?
Let's continue with the previous example to see if the slot function is executed in the main thread or in the threads.
Theorem two emphasizes two concepts: the thread that sends the signal and the thread that the receiver is attached to . The slot function is the thread of the object we created in main, where thread is attached to the main thread
- The queue connection tells us that the slot function executes on the thread that the recipient is attached to. That is, the slot is executed on the main thread
- The direct connection tells us that the slot function executes on the thread that sends the signal. What is the signal sent on that thread?? Indefinite!
- Automatic connection tells us: The two are different, the same as the queue connection. That is, the slot executes on the main thread
Is it too round? (To understand these words thoroughly, you may need to look at the Qtmeta-object system and the Qt event System)
What do we do?
If you do not understand the last two sections, remember the following words (oneself summed up, in terms of estimates will be less accurate).
- Qthread is used to manage threads, the threads it attaches to and the threads it manages are not the same thing.
- The thread on which Qthread is attached is the thread that executes Qthread t (0) or Qthread * t=new qthread (0). That's the main thread of our place.
- The thread that Qthread manages is the thread that run starts. That is, the secondary thread
- Because the Qthread object is attached to the main thread, his slot function executes in the main thread, not the secondary thread. Unless:
- Qthread object attached to sub-line approached (via Movetothread)
- Slots and signals are directly connected, and the signal is emitted in the secondary thread
- But the last two solutions are not good, because qthread is not so used (Bradley t.hughes)
OK, no more text to add, look at the code, I guess we'll be easy.
Main thread (signal) Qthread (slot)
This is a commonly used method in Qt Manual and examples. But since manual does not say that the slot function is executed in the main thread, many people think it should be executed on the secondary threads.
- Define a Dummy class to signal
- Define a Thread class to receive the signal
- The run function is overloaded to print ThreadID
#include /QCoreApplication> #include /QObject> #include /qthread> # include /qdebug> class dummy:public qobject { q_object public: Dummy () {} public slots: void emitsig () { emit sig (); } signals: void sig (); }; class thread:public qthread { q_object public: thread (qobject* parent=0): Qthread (parent) { //movetothread (this); } public slots: void slot_main () { qdebug () << "from thread Slot_main:" << Currentthreadid (); } protected: void run () { qdebug () << thread thread: < <currentthreadid (); exec (); } }; #include "Main.moc" int main (INT&NBSP;ARGC, char *argv[]) { qcoreapplication a (ARGC,&NBSP;ARGV); qDebug () < < "main thread:" <<qthread:: Currentthreadid (); thread thread; dummy dummy; qobject::
Connect(&dummy, SIGNAL (Sig ()), &thread, SLOT (Slot_main ())); Thread.Start (); Dummy.emitsig (); return A.exec (); }
then see the result (the exact value changes every time, but the conclusion is unchanged)
Main THREAD:0X1A40 from thread slot_main:0x1a40 thread Thread:0x1a48
See, the Slot function thread is the same as the main line!
If you have seen the example of Qt , you will find that the Qthread in the slot and the run function in conjunction with the object, will be locked with Qmutex. Why?
Because slots and run are in different threads, synchronization between threads is required!
What if you want the slot function slot to run on a sub-thread (for example, if it does a time-consuming operation that will cause the main thread to die)?
- Note: The dummy signal is emitted on the main thread, and the receiver thread is also in the main thread.
- Referring to our previous conclusions, it is easy to think of:
- Would you like to change thread-dependent threads to a secondary thread?
- This is also done with the commented out Movetothread (this) in the code, minus the comments, and you'll notice that the slots run in the secondary thread
Main thread:0x13c0 thread thread:0x1de0 from thread slot_main:0x1de0
This can work, but this is the use of Bradley T. Hughes's strong critique . The recommended method is given later.
Signal in run and Qthread in slot
- defines a Dummy class that emits its signal in run
- can also emit a signal from the thread class in run instead of Dummy (the effect is exactly the same)
- qthread definition Slot function, overloading the Run function
#include/qcoreapplication> #include/qobject> #include/qthread> #include/qdebug> class Dummy:public Qobject {q_object public:dummy (qobject* parent=0): Qobject (parent) {} public slots:void Emitsig () {emit sig ();} Signals : void Sig (); }; Class Thread:public Qthread {q_object public:thread (qobject* parent=0): Qthread (parent) {//movetothread (this); Slots:void Slot_thread () {qdebug () << "from thread Slot_thread:" <<currentthreadid ();} Signals:void Sig (); Protected:void run () {qdebug () << "thread Thread:" <<currentthreadid (); Dummy Dummy;
Connect(&dummy, SIGNAL (Sig ()), this, SLOT (Slot_thread ())); Dummy.emitsig (); exec (); } }; #include "Main.moc" int main (int argc, char *argv[]) {qcoreapplication A (argc, argv); Qdebug () << "main thread:" <& Lt Qthread::currentthreadid (); Thread thread; Thread.Start (); return A.exec (); }
Want to see the results?
Main thread:0x15c0 thread thread:0x1750 from thread slot_thread:0x15c0
- In fact, no suspense, it must be the main thread
- The thread object itself is in the main thread. So its slots are going to be executed in the main thread.
How to solve it?
- (method i) mentioned movetothread, here can be used, and can solve the problem. When the same, is the object of being criticized.
- (method Two) Note oh, here our signal when the second thread, compared to connect connection mode, will find:
- With a direct connection, the slot function executes on the secondary thread (the signal-emitting thread)
- This method is not very good because you need to handle the synchronization of the slot and the thread on which it is located . Need to qmutex a class of things
Recommended method
Awaited began to come out.
In fact, this method is too simple, too useful. Define a generic Qobject derived class, and then move its objects to qthread. There is no need to consider multithreading when using signals and slots. Also do not use Qmutex to synchronize,Qt event Loop will automatically handle this.
#include /QCoreApplication> #include /QObject> #include /qthread> # include /qdebug> class dummy:public qobject { q_object public: Dummy (qobject* parent=0): Qobject (parent) {} public slots: void emitsig () { emit sig (); } signals: void sig (); }; class object:public Qobject { q_object public: object () {} public slots: void slot () { qdebug () << "from thread slot:" <<qthread::currentthreadid (); } }; #include " Main.moc " int main (int argc, char *argv[]) { qcoreapplication a (argc, &NBSP;ARGV); qdebug () << "main thread:" <<qthread::currentthreadid (); qthread thread; object obj; dummy dummy; obj.movetothread (&thread); QObject::
Connect(&dummy, SIGNAL (Sig ()), &obj, slot ()); Thread.Start (); Dummy.emitsig (); return A.exec (); }
Result: main thread:0x1a5c from Thread slot:0x186c
Well, the slot does not run in the main thread (so simple isn't it worth cheering for?). )
Put a good code in the following
#include <QtWidgets/QApplication>#include<QObject>#include<QThread>#include<QDebug>classDUMMY1: PublicQobject {q_object Public: //Dummy1 (qobject* parent = 0): Qobject (parent)// {} PublicSlots:voidEmitsig () {emit sig (); }signals:voidsig ();};classObject: PublicQobject {q_object Public: Object () {} PublicSlots:voidslot () {qdebug ()<<"From thread slot:"<<Qthread::currentthreadid (); }};intMainintargcChar*argv[]) {Qcoreapplication A (argc, argv); Qdebug ()<<"Main thread:"<<Qthread::currentthreadid (); Qthread thread; Object obj; DUMMY1 dummy; //Obj.movetothread (&thread);Qobject::connect (&dummy, SIGNAL (Sig ()), &obj, slot (slot ())); Thread.Start (); Dummy.emitsig (); returna.exec ();}
Note that the run code is not placed in a CPP
QT signal and slot on which thread is executing the problem