QT provides support for threading, the basic form of platform-independent threading classes, thread-safe event passing, and a global QT library mutex allows you to invoke QT methods from different threads.
This document is provided to listeners who have a wealth of knowledge and experience in multithreaded programming. Recommended reading:
- Threads PRIMER:A Guide to multithreaded programming
- Thread time:the multithreaded Programming Guide
- Pthreads programming:a POSIX Standard for Better multiprocessing (O ' Reilly nutshell)
- Win32 multithreaded Programming
Warning: all GUI classes (for example, Qwidget and its subclasses), operating system core classes (such as qprocess) and network classes are not thread-safe.
Qregexp uses a static cache and is also not thread-safe, even if the Qregexp object is protected by using Qmutex.
Thread class
The most important class is qthread, which means that to start a new thread, you start executing the Qthread::run () that you re-implement. This is similar to the Java threading class.
In order to write a thread, it is necessary to protect the data when two threads simultaneously want to access the same data. So there is also a Qmutex class, where a thread can lock the mutex and the other thread cannot lock the mutex after it is locked, and the thread attempting to do so will be blocked until the mutex is freed. For example:
Class MyClass {public : void Dostuff (int);
Private
Qmutex Mutex;
int A;
int b; }; Here A is set to C,b for c*2.
void MyClass::d ostuff (int c) {
Mutex.lock ();
A = C;
b = c * 2;
Mutex.unlock ();
This guarantees that only one thread at a time can enter MyClass::d Ostuff (), so b will always be equal to c * 2.
Another thread also needs to wait for the other thread to wake up under a given condition, and the Qwaitcondition class is provided. The thread waits for the condition qwaitcondition points out what has happened and the blocking will continue until this happens. When something happens, qwaitcondition can wake up one or all of the threads waiting for the event. (This is the same functionality as the POSIX thread condition variable and it is also an implementation on UNIX.) For example
#include <qapplication.h>
#include <qpushbutton.h>
Global condition variables
Qwaitcondition Mycond; Worker class implementation
Class Worker:public Qpushbutton, public qthread
{ Q_object
Public
Worker (Qwidget *parent = 0, const char *name = 0)
: Qpushbutton (parent, name)
{
SetText ("Start working");
Connect the signals inherited from Qpushbutton and our slotclicked () method
Connect (this, SIGNAL (clicked ()), SLOT (slotclicked ()));
Call the start () method inherited from Qthread ... This will start the execution of the thread immediately
Qthread::start ();
}
Public Slots:
void Slotclicked ()
{ //wake up a thread waiting for this condition variable
Mycond.wakeone ();
}
Protected
void Run ()
{
//This method will be called by the newly created thread ...
while (TRUE) {
//Lock the application mutex and set the window caption to indicate that we are waiting to start working
Qapp->lock ();
setcaption ("Waiting");
Qapp->unlock ();
Wait until we are told we can continue
Mycond.wait ();
If we get here, we've been woken up by another thread ... Let's set the title to show that we're working
Qapp->lock ();
Setcaption ("working!");
Qapp->unlock ();
This may take some time, a few seconds, a few minutes or a few hours, and so on, because this is a thread that is separate from the GUI thread, and the GUI thread does not stop when handling events ...
Do_complicated_thing ();
}
}
};
The main thread-all GUI events are handled by this threading.
int main (int argc, char **argv)
{
Qapplication app (argc, argv);
Create a worker ... When we do this, the worker will run in a thread
Worker Firstworker (0, "worker");
App.setmainwidget (&worker);
Worker.show ();
return app.exec ();
}
As soon as you press the button, the program wakes up the worker thread, and the thread will do some work and then come back and wait to be told to do more work. If the worker thread is working when the button is pressed, nothing will happen. When the thread finishes working and calls Qwaitcondition::wait again (), then it is started.
Thread-Safe Event delivery
In Qt, a thread is always an event thread--indeed, threads pull events out of the window system and distribute them to widgets. static method Qthread::p ostevent to pass events from the thread instead of the event thread. The event thread is awakened and the event is distributed in the event thread as if it were a normal window system event. For example, you can force a widget to redraw by doing a different thread like this:
Qwidget *mywidget;
Qthread::p ostevent (Mywidget, New Qpaintevent (qrect (0, 0, 100, 100));
This (asynchronously) causes the mywidget to redraw a 100*100 square area.
QT Library Mutex
The QT library mutex provides a way to call the Qt method from a thread rather than an event thread. For example:
Qapplication *qapp;
Qwidget *mywidget;
Qapp->lock ();
Mywidget->setgeometry (0,0,100,100);
Qpainter p; P.begin (mywidget); P.drawline (0,0,100,100); P.end (); Qapp->unlock ();
Calling a function without using mutexes in QT typically results in unpredictable outcomes. A GUI-related function that calls QT from another thread requires the use of the QT library mutex. In this case, all possible final access to any graphics or window system resources is GUI-related. Using a container class, a string, or an input/output class, if the object is used by only one thread, no mutex is required.
Warned
There are a few things to be aware of when threading programming:
- do not make any blocking operations when using the QT library mutex. This will freeze the event loop. The
- confirms that you lock a recursive Qmutex the same number of times and locks, and cannot be more or less.
- Locks the QT application mutex before invoking anything except the QT container and the tool class.
- beware of implicitly sharing classes, you should avoid using operator = () between threads to copy them. This will be improved in the future major or minor releases of Qt.
- Beware of QT classes that are not designed to be thread-safe, for example, qptrlist application interfaces are not thread-safe and if different threads need to traverse a qptrlist, they should call Qptrlist::first () Previously locked and unlocked after reaching the finish, rather than locking and unlocking before or after the Qptrlist::next ().
- confirms that only objects that are inherited and that use Qwidget, Qtimer, and Qsocketnotifier are created in the GUI thread. On some platforms, creating such an object in a thread that is not a GUI thread will never accept events from the underlying window system. The
- is similar to the above and only uses the Qnetwork class in the GUI thread. A frequently asked question is whether a qsocket can be used in multiple threads. This is not necessary, because all the Qnetwork classes are asynchronous.
- do not attempt to invoke the Processevents () function in a thread that is not a GUI thread. This also includes qdialog::exec (), Qpopupmenu::exec (), Qapplication::p rocessevents () and others.
- in your application, do not mix the normal QT library with the support thread's QT library. This means that if your program uses a thread-supported QT library, you should not connect to the normal QT library, load the normal QT library dynamically, or dynamically connect to other libraries or plugins that rely on the common Qt Library. On some systems, this can cause static data that is used in the QT library to become unreliable.
QT provides support for threading in three different forms. They are, one, platform-independent thread class, two, thread-safe event delivery, three, cross-thread signal-slot connection. This makes it easier to develop a lightweight multithreaded QT program and take advantage of multiprocessor machines. Multithreaded programming is also a useful pattern that is used to resolve long-run operations without the user interface losing response.
Qt Threading Class
Qt contains some of the following thread-related classes:
Qthread provides a way to start a new thread
Qthreadstorage provides per-thread data storage
Qmutex offers mutually exclusive locks, or mutexes
Qmutexlocker is a handy class that can automatically locking and unlock Qmutex
Qreadwritelock provides a lock that can read and write operations simultaneously
Qreadlocker and Qwritelocker are convenience classes, which automatically locking and unlocks Qreadwritelock
Qsemaphore provides an integer semaphore, which is a generalization of the mutex
Qwaitcondition provides a way for a thread to hibernate until it is awakened by another thread.
Qt Advanced Threading Class
Qtconcurrent Opening thread transactions
Qfuturewatcher Observing Thread Status
Qfuture Thread Startup class
Qthread Creating Threads
To create a thread, subclass the Qthread and rewrite its run () function, for example:
Class Mythread:public Qthread
{
Q_object
Protected
void run ();
};
void Mythread::run ()
{
...
}
You can then call START,QT to create a thread and execute the code in the Run () function in the threads, noting that the UI is non-thread-safe.
Qtconcurrent Creating Threads
Qtconcurrent the method of creating a thread is much more, and the qtconcurrent itself is more special, if the system has idle threads, it dispatches idle threads, and no idle threads will create a thread.
(Note: Qtconcurrent creates thread qthreadpool management, if it exceeds the maximum number of threads, it will enter the queue wait), qtconcurrent the method of creating threads, the following example map function:
Qimage scale (const qimage &image)
{
Qdebug () < < "Scaling image in Thread" << qthread::currentthread ();
Return image.scaled (Qsize (+), Qt::ignoreaspectratio, qt::smoothtransformation);
}
int main (int argc, char *argv[])
{
Qapplication app (argc, argv);
const int imagecount = 20;
Create A list containing imagecount images.
Qlist images;
for (int i = 0; i < Imagecount; ++i)
Images.append (Qimage, qimage::format_argb32_premultiplied);
Use qtconcurrentblocking::mapped to apply the scale function to all the
Images in the list.
Qlist thumbnails = qtconcurrent::blockingmapped (images, scale);
return 0;
}
Qt thread Synchronization
Qmutex, Qreadwritelock, Qsemaphore, qwaitcondition provide a means of thread synchronization. The main idea of using threads is to expect them to be executed as concurrently as possible, while some key points need to be stopped or waiting between them. For example, if two threads attempt to access the same global variable at the same time, the result may not be as desired.
Qmutex
The Qmutex provides mutually exclusive locks, or mutexes. At most one thread has a mutex at a time, and if a thread tries to access a mutex that is already locked, it will hibernate until the thread that owns the mutex unlocks the mutex. Mutexes is commonly used to protect shared data access.
Qreadwriterlock
Qreadwriterlock is similar to Qmutex, except that it treats "read", "write" access differently. It enables multiple readers to access data in a common time. Using Qreadwritelock instead of Qmutex can make multi-threaded routines more concurrency-capable.
Qreadwritelock lock;
void Readerthread::run ()
{
Lock.lockforread ();
Read_file ();
Lock.unlock ();
}
void Writerthread::run ()
{
Lock.lockforwrite ();
Write_file ();
Lock.unlock ();
}
Qsemaphore
Qsemaphore is the generalization of Qmutex, which protects a certain number of identical resources, and in contrast, a mutex protects only one resource. In the following example, Qsemaphore is used to control access to the ring buffer, which is shared by the producer thread and the consumer thread. Producers continue to write data to the buffer until the end of the buffer, and then start from scratch. Consumers constantly read data from buffers. The semaphore has better concurrency than the mutex, and if we use mutex to control the access to the buffer, then the producer, the consumer cannot access the buffer at the same time. However, we know that at the same time, different threads have no harm in accessing different parts of the buffer.
const int datasize = 100000;
const int buffersize = 8192;
Char Buffer[buffersize];
Qsemaphore freebytes (buffersize);
Qsemaphore usedbytes;
Class Producer:public Qthread
{
Public
void run ();
};
void Producer::run ()
{
Qsrand (Qtime (0,0,0). Secsto (Qtime::currenttime ()));
for (int i = 0; i < datasize; ++i) {
Freebytes.acquire ();
Buffer[i% buffersize] = "ACGT" [(int) Qrand ()% 4];
Usedbytes.release ();
}
}
Class Consumer:public Qthread
{
Public
void run ();
};
void Consumer::run ()
{
for (int i = 0; i < datasize; ++i) {
Usedbytes.acquire ();
fprintf (stderr, "%c", buffer[i% buffersize]);
Freebytes.release ();
}
fprintf (stderr, "\ n");
}
int main (int argc, char *argv[])
{
Qcoreapplication app (argc, argv);
Producer Producer;
Consumer Consumer;
Producer.start ();
Consumer.start ();
Producer.wait ();
Consumer.wait ();
return 0;
}
Qwaitcondition
Qwaitcondition allows a thread to wake up another thread when certain conditions occur. One or more threads can block waiting for a qwaitcondition, setting a condition with wakeone () or Wakeall (). Wakeone () Randomly wakes up one, Wakeall () wakes all.
In the following example, the producer must first check whether the buffer is full (numusedbytes==buffersize), and if so, the thread stops to wait for the buffernotfull condition. If not, produce the data in the buffer, increase the numusedbytes, activate the condition buffernotempty. Use a mutex to protect access to numusedbytes. In addition, qwaitcondition::wait () receives a mutex as a parameter, and the mutex should be initialized to a locked state by the calling thread. The mutex is unlocked before the thread enters hibernation. When a thread is awakened, the mutex is locked, and the transition from the lock state to the wait state is atomic, which prevents the race condition from being generated. When the program starts running, only the producer can work. Consumers are blocked waiting for buffernotempty conditions, and once the producer puts a byte in the buffer, the buffernotempty condition is fired and the consumer thread is awakened.
const int datasize = 100000;
const int buffersize = 8192;
Char Buffer[buffersize];
Qwaitcondition Buffernotempty;
Qwaitcondition Buffernotfull;
Qmutex Mutex;
int numusedbytes = 0;
Class Producer:public Qthread
{
Public
void run ();
};
void Producer::run ()
{
Qsrand (Qtime (0,0,0). Secsto (Qtime::currenttime ()));
for (int i = 0; i < datasize; ++i) {
Mutex.lock ();
if (numusedbytes = = buffersize)
Buffernotfull.wait (&mutex);
Mutex.unlock ();
Buffer[i% buffersize] = "ACGT" [(int) Qrand ()% 4];
Mutex.lock ();
++numusedbytes;
Buffernotempty.wakeall ();
Mutex.unlock ();
}
}
Class Consumer:public Qthread
{
Public
void run ();
};
void Consumer::run ()
{
for (int i = 0; i < datasize; ++i) {
Mutex.lock ();
if (numusedbytes = = 0)
Buffernotempty.wait (&mutex);
Mutex.unlock ();
fprintf (stderr, "%c", buffer[i% buffersize]);
Mutex.lock ();
--numusedbytes;
Buffernotfull.wakeall ();
Mutex.unlock ();
}
fprintf (stderr, "\ n");
}
int main (int argc, char *argv[])
{
Qcoreapplication app (argc, argv);
Producer Producer;
Consumer Consumer;
Producer.start ();
Consumer.start ();
Producer.wait ();
Consumer.wait ();
return 0;
}
http://blog.csdn.net/emdfans/article/details/41745007
QT Multithreaded Programming Summary (i) (all GUI objects are thread insecure)