qt线程学习文档.docx
- 文档编号:9752502
- 上传时间:2023-05-21
- 格式:DOCX
- 页数:19
- 大小:27.33KB
qt线程学习文档.docx
《qt线程学习文档.docx》由会员分享,可在线阅读,更多相关《qt线程学习文档.docx(19页珍藏版)》请在冰点文库上搜索。
qt线程学习文档
Qt多线程
Qt线程类
Qt包含下面一些线程相关的类:
QThread 提供了开始一个新线程的方法
QThreadStorage 提供逐线程数据存储
QMutex 提供相互排斥的锁,或互斥量
QMutexLocker 是一个便利类,它可以自动对QMutex 加锁与解锁
QReadWriterLock 提供了一个可以同时读操作的锁
QReadLocker 与QWriteLocker 是便利类,它自动对QReadWriteLock 加锁与解锁
QSemaphore 提供了一个整型信号量,是互斥量的泛化
QWaitCondition 提供了一种方法,使得线程可以在被另外线程唤醒之前一直休眠。
Qt线程的创建
Qt线程中有一个公共的抽象类,所有的线程都是从这个QThread抽象类中派生的,要实现QThread中的纯虚函数run(),run()函数是通过start()函数来实现调用的。
1 class MyThread :
public QThread {
2 public :
3 virtual void run();
4 };
5
6 void MyThread:
:
run()
7 {
8 for ( int count = 0 ; count < 20 ; count ++ ) {
9 sleep( 1 );
10 qDebug( " Ping!
" );
11 }
12 }
13
14 int main()
15 {
16 MyThread a;
17 MyThread b;
18
19 a.start(); // 自动调用run(),否则即使该线程创建,也是一开始就挂起
20 b.start();
21 // 要等待线程a,b都退出
22 a.wait();
23 b.wait();
24 }
25
Qt线程同步
1.QMutex
QMutex (bool recursive=FALSE)
virtual ~QMutex ()
void lock () //试图锁定互斥量。
如果另一个线程已经锁定这个互斥量,那么这次调用将阻塞 直到那个线程把它解锁。
void unlock ()
bool locked ()
bool tryLock () //如果另一个进程已经锁定了这个互斥量,这个函数返回假,而不是一直等到这个锁可用为止,比如,它不是阻塞的。
1 // Qt
2 QMutex mutex;
3 void someMethod()
4 {
5 mutex. lock ();
6 qDebug( " Hello " );
7 qDebug( " World " );
8 mutex.unlock();
9 }
10
11 // 用Java的术语,这段代码应该是:
12 void someMethod()
13 {
14 synchronized {
15 qDebug( " Hello " );
16 qDebug( " World " );
17 }
18 }
不过在Qt中我们可用通过另一个类来简化这种应用,因为如果使用QMutex.lock()而没有对应的使用QMutex.unlcok()的话
就会造成死锁,别的线程永远也得不到接触该mutex锁住的共享资源的机会。
尽管可以不使用lock()而使用tryLock(timeout)
来避免因为死等而造成的死锁(tryLock(负值)==lock()),但是还是很有可能造成错误。
对于上述的情况MFC中用CSingleLock或MultiLock,Boost中用boost:
:
mutex:
:
scoped_lock来进行解决,而在Qt中用
QMutexLocker来进行解决。
下面是没有采用 QMutexLocker的例子和采用 QMutexLocker的方案。
2.QMutexLocker
thiscomplexfunctionlocksa QMutex uponenteringthefunctionandunlocksthemutexatalltheexitpoints
1 int complexFunction( int flag)
2 {
3 mutex. lock ();
4
5 int retVal = 0 ;
6
7 switch (flag) {
8 case 0 :
9 case 1 :
10 mutex.unlock();
11 return moreComplexFunction(flag);
12 case 2 :
13 {
14 int status = anotherFunction();
15 if (status < 0 ) {
16 mutex.unlock();
17 return - 2 ;
18 }
19 retVal = status + flag;
20 }
21 break ;
22 default :
23 if (flag > 10 ) {
24 mutex.unlock();
25 return - 1 ;
26 }
27 break ;
28 }
29
30 mutex.unlock();
31 return retVal;
32 }
Thisexampleincreasesthelikelihoodthaterrorswilloccur.UsingQMutexLockergreatlysimplifiesthecode,andmakesitmorereadable:
1 int complexFunction( int flag)
2 {
3 QMutexLocker locker( & mutex);
4
5 int retVal = 0 ;
6
7 switch (flag) {
8 case 0 :
9 case 1 :
10 return moreComplexFunction(flag);
11 case 2 :
12 {
13 int status = anotherFunction();
14 if (status < 0 )
15 return - 2 ;
16 retVal = status + flag;
17 }
18 break ;
19 default :
20 if (flag > 10 )
21 return - 1 ;
22 break ;
23 }
24
25 return retVal;
26 }
Now,themutexwillalwaysbeunlockedwhentheQMutexLockerobjectisdestroyed(whenthefunctionreturnssincelocker isanautovariable) . 即使在抛出异常的情况下也可以使用。
3.QReadWriteLock
用mutex进行线程同步有一个问题就是mutex只允许某个时刻只允许一个线程对共享资源进行访问,如果同时有多个线程对共享
资源进行读访问,而只有一个写操作线程,那么在这种情况下如果采用mutex就成为程序运行性能的瓶颈了。
在这种情况下Qt下采用
QReadWriteLock来实现多个线程读,一个线程写。
写线程执行的时候会阻塞所有的读线程,而读线程之间的运行不需要进行同步。
1 MyData data;
2 QReadWriteLock lock ;
3 void ReaderThread:
:
run()
4 {
5
6 lock .lockForRead();
7 access_data_without_modifying_it( & data);
8 lock .unlock();
9
10 }
11 void WriterThread:
:
run()
12 {
13
14 lock .lockForWrite();
15 modify_data( & data);
16 lock .unlock();
17
18 }
19
20
QReadWriterLock 与QMutex相似,除了它对"read","write"访问进行区别对待。
它使得多个读者可以共时访问数据。
使用QReadWriteLock而不是QMutex,可以使得多线程程序更具有并发性。
4.QReadLocker和QWriteLocker
对于QMutex有QMutexLocker来简化使用,而对于QReadWriteLock有 QReadLocker 和 QWriteLocker。
Here'sanexamplethatusesQReadLockertolockandunlockaread-writelockforreading:
QReadWriteLock lock ;
QByteArray readData()
{
QReadLocker locker(&lock);
return data;
}
Itisequivalenttothefollowingcode:
QReadWriteLock lock ;
QByteArray readData()
{
lock.lockForRead();
lock.unlock();
return data;
}
5.QSemaphore
QSemaphore 是QMutex 的一般化,它可以保护一定数量的相同资源,与此相对,一个mutex只保护一个资源。
下面例子中,使用QSemaphore 来控制对环状缓冲区 的访问,此缓冲区被生产者线程和消费者线程共享。
生产者不断向缓冲写入数据直到缓冲末端 ,消费者从缓冲不断从缓冲头部 读取数据。
信号量比互斥量有更好的并发性 ,假如我们用互斥量来控制对缓冲的访问,那么生产者,消费者不能同时访问缓冲 。
然而,我们知道在同一时刻,不同线程访问缓冲的不同部分并没有什么危害。
QSemaphoresemaphore
(1);| QMutexmutex;
Qsemaphore.acquire(); | Qmutex.lock();
Qsemaphore.release(); | Qmutex.unlock();
PublicFunctions
∙QSemaphore (int n =0)
∙~QSemaphore ()
∙void acquire (int n =1)
∙int available ()const
∙void release (int n =1)
∙bool tryAcquire (int n =1)
∙bool tryAcquire (int n ,int timeout )
Semaphoressupporttwofundamentaloperations, acquire ()and release ():
∙acquire(n) triestoacquire n resources.Iftherearen'tthatmanyresourcesavailable,thecallwillblockuntilthisisthecase.
∙release(n ) releases n resources.
∙tryAcquire () returnsimmediatelyifitcannotacquiretheresources
∙available () returnsthenumberofavailableresourcesatanytime.
Example:
QSemaphore sem( 5 ); // sem.available() == 5
sem.acquire( 3 ); // sem.available() == 2
sem.acquire( 2 ); // sem.available() == 0
sem.release( 5 ); // sem.available() == 5
sem.release( 5 ); // sem.available() == 10
sem.tryAcquire( 1 ); // sem.available() == 9, returns true
sem.tryAcquire( 250 ); // sem.available() == 9, returns false
生产者线程写数据到buffer直到缓冲末端,然后重新从buffer的头部开始写。
显然producer线程和consumer线程是需要进行同步的,If theproducergeneratesthedatatoofast,itwilloverwritedatathattheconsumerhasn'tyetread;iftheconsumerreadsthedatatoofast,itwillpasstheproducerandreadgarbage.
Acrudewaytosolvethisproblemistohavetheproducerfillthebuffer,thenwaituntiltheconsumerhasreadtheentirebuffer,andsoon. 显然这样做效率是比较低的。
1 const int DataSize = 100000 ;
2 const int BufferSize = 8192 ;
3 char buffer[BufferSize];
4
5 // When the application starts, the reader thread will start
// acquiring "free" bytes and convert them into "used" bytes
6 QSemaphore freeBytes(BufferSize); // producer线程在此区域写入数据 ,初始资源数量为BufferSize
7 QSemaphore usedBytes; // consumer线程读取此区域的数据,初始资源数量为0
8
9
10 // For this example, each byte counts as one resource.
11 // In a real-world application, we would probably operate on larger
// units (for example, 64 or 256 bytes at a time)
12 class Producer :
public QThread
13 {
14 public :
15 void run();
16 };
17 //生产者每acquire一次就,使用掉Buffer个资源中的一个,而写入的字符存入到buffer数组中
//从而消费者可用读取字符,从而消费者获取一个资源
18 void Producer:
:
run()
19 {
20 //qsrand(QTime(0,0,0).secsTo(QTime:
:
currentTime()));
21 for ( int i = 0 ; i < DataSize; ++ i) {
22 freeBytes.acquire ();
23 buffer[i % BufferSize] = " ACGT " [( int )qrand() % 4 ];
24 usedBytes.release ();
25 }
26 }
27
28 class Consumer :
public QThread
29 {
30 public :
31 void run();
32 };
33
34 void Consumer:
:
run()
35 {
36 for ( int i = 0 ; i < DataSize; ++ i) {
37 usedBytes.acquire ();
38 fprintf(stderr, " %c " , buffer[i % BufferSize]);
39 freeBytes.release ();
40 }
41 fprintf(stderr, " \n " );
42 }
43 // Finally, in main(), we start the producer and consumer threads.
// What happens then is that the producer converts some "free" space
// into "used" space, and the consumer can then convert it back to // "free" space.
46 int main( int argc, char * argv[])
47 {
48 QCoreApplication app(argc, argv);
49 Producer producer;
50 Consumer consumer;
51 producer.start();
52 consumer.start();
53 producer.wait();
54 consumer.wait();
55 return 0 ;
56 }
producer的run函数:
当producer线程执行run函数,如果buffer中已经满了,而没有consumer线程没有读,这样producer就不能再往buffer
中写字符。
此时在 freeBytes.acquire 处就阻塞直到 consumer线程读(consume)数据。
一旦producer获取到一个字节(资源)
就写如一个随机的字符,并调用 usedBytes.release 从而 consumer线程获取一个资源可以读一个字节的数据了。
consumer的run函数:
当consumer线程执行run函数,如果buffer中没有数据,就是资源=0,则consumer线程在此处阻塞。
直到producer线程执行
写操作,写入一个字节,并执行usedBytes.release 从而使得consumer线程的可用资源数=1。
则consumer线程从阻塞状态中退出,
并将 usedBytes 资源数-1,当前资源数=0。
6.QWaitCondition
∙QWaitCondition ()
∙virtual ~QWaitCondition ()
∙bool wait (QMutex * mutex,unsigned long time=ULONG_MAX)
∙void wakeOne ()
∙void wakeAll ()
Publicfunction:
boolQWaitCondition:
:
wait( QMutex * mutex,unsigned long time=ULONG_MAX)
1)释放锁定的mutex
2)在线程对象上等待
mutex必须由调用线程进行初锁定。
注意调用wait的话,会自动调用unlock解锁之前锁住的资源,不然会造成死锁。
线程1等待线程2来改变共享资源,从而达到一定的条件然后发出信号,使得线程1
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- qt 线程 学习 文档