I saw manual of QT last night and suddenly found that the next version of QT (qt4.7.4, qt4.8, and so on) added a special article about multithreading:
Note:
- This link will expire in the future, but you can simply check the manual of QT.
- This article does not strictly translate dbzhang800
Thread used
There is basically a thread usage scenario:
- The processing speed is faster by using multiple cores of the processor.
- To maintain the response of GUI threads or other highly real-time threads, move time-consuming operations or blocked calls to other threads.
When to use other technologies to replace threads
Developers must be very careful when using threads. It is easy to start the thread, but it is difficult to ensure that all the shared data is consistent. It is often difficult to solve the problem, because it may only appear once or only in a specific hardware configuration within a period of time.Some alternative technologies should be considered before creating threads to solve some problems.
:
Alternative Technology |
Annotation |
Qeventloop: processevents () |
It is called repeatedly in a time-consuming computing operationQeventloop: processevents () It can prevent false positives on the interface. However, this scheme is not very scalable because the function may be called too frequently or not frequently. |
Qtimer |
Background processing operations can sometimes be easily completed using timer in a slot executed at a certain time point in the future. When no other events need to be processed, the timer timeout event with a time interval of 0 is correspondingly |
Qsocketnotifier
Qnetworkaccessmanager
Qiodevice: readyread () |
This is an alternative technology that replaces the situation where one or more threads block reading on a slow network. As long as the response part of the computing can be quickly executed, this design is better than the synchronization waiting in the process. This design is less error-prone and energy-saving than a thread ). In many cases, it also has performance advantages. |
Generally, we recommend that you use only the security and tested solutions to avoid introducing the concept of special threads. Qtconcurrent provides an easy-to-use interface for distributing tasks to all the cores of the processor. The thread code is completely hidden in the qtconcurrent framework, so you don't have to consider the details. However, qtconcurrent cannot be used when the thread needs to communicate, and it should not be used to handle blocking operations.
Which technology of QT thread should be used?
Sometimes, you don't just need to run a function in the context of another thread. You may need an object in another thread to provide services for GUI threads. Maybe you want to poll the hardware port in another always-running thread and send a signal to the GUI thread when something of interest occurs. Qt provides various solutions for developing multi-threaded applications.The solution depends on the purpose of the new thread and the thread lifecycle.
Lifecycle |
Development Task |
Solution |
One call |
Run a function in another thread and exit the thread when the function is completed. |
Write Functions and useQtconcurrent: Run Run it |
Derived qrunnable, useQthreadpool: globalinstance ()-> Start () Run it |
Derive qthread and implement it againQthread: Run () , UseQthread: Start () Run it |
One call |
All items in a container need to be operated. Use all available cores of the processor. A common example is to generate a thumbnail from the image list. |
Qtconcurrent The map () function is provided to apply operations to every element in the container. The fitler () function is provided to select container elements and the reduce function is specified as an option to combine the remaining elements. |
One call |
One time-consuming operation needs to be put into another thread. During processing, the status information needs to be sent to the GUI thread. |
Use qthread to re-implement the run function and send signals as needed. Use the queued connection method of the signal slot to connect the signal to the slot function of the GUI thread. |
Persistent running |
Objects that exist in another thread need to execute different tasks as required. This means that the worker thread needs two-way communication. |
Derive a qobject object and implement the required signals and slots. Move the object to a thread that runs an event loop and communicate with each other using the queued method. |
Persistent running |
Objects that exist in another thread, execute repeated tasks such as polling ports, and communicate with GUI threads. |
Same as above, but a timer is used for polling in the work thread. Even so, the best solution to handle polling is to completely avoid it. Sometimes qsocketnotifer is an alternative. |
Qt thread Basics
Qthread is a convenient cross-platform abstraction of the platform's native threads. It is very easy to start a thread. Let's take a short look at the code: generate a thread that outputs "hello" and exits in the thread.
// hellothread/hellothread.h class HelloThread : public QThread { Q_OBJECT private: void run(); };
We derive a class from qthread and re-implement the run method.
// hellothread/hellothread.cpp void HelloThread::run() { qDebug() << "hello from worker thread " << thread()->currentThreadId(); }
The run method contains the code that will be run in another thread. In this example, a message containing the thread ID is printed.
Qthread: Start ()
It will be called in another thread.
int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); HelloThread thread; thread.start(); qDebug() << "hello from GUI thread " << app.thread()->currentThreadId(); thread.wait(); // do not exit before the thread is completed! return 0; }
Qobject and thread
Qobject has thread affinity? Association? Attachment? Dbzhang800 20110618], in other words, it lives in a specific thread. This means that qobject saves the pointer to the current thread during creation. This information becomes useful when an event is distributed using postevent. Events are placed in the event loop of the corresponding thread. If the thread to which the qobject is attached has no event loop, the event will never be passed.
To start the event loop, exec () must be called in run (). Thread association can be changed through movetothread.
As mentioned above, developers must always be cautious when calling object methods from other threads. Thread association does not change this situation. Some methods are marked as thread security in QT document. Postevent () is a noteworthy example. A thread-safe method can be called in different threads at the same time.
Generally, some methods do not support concurrent access, the non-thread-safe method of calling objects in other threads may work properly before thousands of concurrent accesses that cause unexpected behavior. Writing Test code does not completely ensure the correctness of the thread, but it is still important. In Linux, valgrind and helgrind help detect thread errors.
The internal structure of qthread is very interesting:
- Qthread does not exist in the new thread that executes run. It exists in the old thread.
- Most of the member methods of qthread are thread control interfaces and are designed to be called from the old thread. Do not use movetothread () to move this interface to a newly created thread. Calling movetothread (this) is considered a bad practice.
- Exec () and static methods usleep (), msleep (), and sleep () should be called in the newly created thread.
- Other members defined in the qthread subclass can be accessed in two threads. Developers are responsible for access control. A typical policy is to set member variables before start () is called. Once the worker thread starts running, the master thread should not operate on other members. When the worker thread is terminated, the master thread can access other members again. This is a convenient policy for passing parameters before the thread starts and collecting results after the end.
Qobject must always be in the same thread as parent. There is an astonishing consequence for the objects generated in run:
void HelloThread::run() { QObject *object1 = new QObject(this); //error, parent must be in the same thread QObject object2; // OK QSharedPointer <QObject> object3(new QObject); // OK }
Use mutex to protect data integrity
Mutex is an object that has the lock () and unlock () methods and remembers whether it is locked. Mutex is designed to be called from multiple threads. If the semaphore is not locked, lock () will return immediately. The next call from another thread will find that the semaphore is locked, and lock () will block the thread until other threads call unlock (). This feature ensures that the code segment can only be executed by one thread at a time.
Use event loops to prevent data corruption
The QT event loop is a very valuable tool for inter-thread communication. Each thread can have its own event loop. One safe way to call a slot in another thread is to place the call in the event loop of another thread. This ensures that the target object can complete the currently running member function before calling another member function.
So how can we put a member call in an event loop? Qt has two methods to do this. One method is to connect through the queued signal slot; the other is to dispatch an event using qcoreapplication: postevent. The queued signal slot connection is an asynchronous signal slot connection. Internal implementation is based on posted events. After the signal parameters are placed in the event loop, the call of the signal function will be immediately returned.
When the connected slot function is executed depends on other operations of the event loop.
Event loop communication eliminates the deadlock problem when we use mutex. This is why we recommend using event loops instead of locking objects with mutex.
Process asynchronous execution
One way to get the result of a working thread is to wait for the thread to terminate. In many cases, a blocking wait is unacceptable. The alternative to blocking wait is that asynchronous results are passed through the posted event or queued signal slot. Because the operation result will not appear in the next line of the source code, but in a slot located in the other part of the source file, this will produce a certain amount of overhead, because, but in the slot located elsewhere in the source file. Qt developers are used to working with this asynchronous behavior because it is very similar to the event-driven programming used in Gui programs.