偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

關(guān)于 Qt 線程同步實(shí)例介紹

移動(dòng)開(kāi)發(fā)
關(guān)于 Qt 線程同步實(shí)例介紹,實(shí)現(xiàn)同步的一個(gè)實(shí)例,詳細(xì)內(nèi)容請(qǐng)看本文。

Qt 線程同步實(shí)例介紹是本文介紹的內(nèi)容,在Qt中使用線程,沒(méi)有Mfc中那么繁瑣,它提供了QThread線程類(lèi),提供了創(chuàng)建一個(gè)新的方法。線程通過(guò)重載QThread::run()函數(shù)來(lái)完成其操作的,這一點(diǎn)與Java中的線程類(lèi)相似。

實(shí)現(xiàn)一個(gè)簡(jiǎn)單的繼承自QThread的用戶線程類(lèi),代碼如下。

  1. class Thread : public QThread   
  2. {  
  3. public:  
  4.     Thread();  
  5.     void stop();  
  6. protected:  
  7.     virtual void run();  
  8. private:  
  9.     bool m_stop;  
  10. };  
  11. Thread::Thread()  
  12. {  
  13.     m_stop = false;  
  14. }  
  15. void Thread::stop()  
  16. {  
  17.     m_stop = true;  
  18. }  
  19. void Thread::run()  
  20. {  
  21.     while (!m_stop)  
  22.     {  
  23.         sleep(1);  
  24.         qDebug("vic.MINg!");  
  25.     }  
  26.     qDebug("end!");  

在以上的示例中可以看出,線程的編寫(xiě)并不難!

啟動(dòng)線程的時(shí)候可以,調(diào)用函數(shù)QThread::start(),開(kāi)始Thread線程對(duì)象。

停止線程的時(shí)候可以,調(diào)用函數(shù)QThread::terminate(),但是terminate()函數(shù)并不會(huì)立刻終止線程,該線程何時(shí)終止取決于操作系統(tǒng)的調(diào)度策略。需要注意的是,terminate()函數(shù)過(guò)于毒辣,它可能在線程執(zhí)行的任意一步終止執(zhí)行,從而產(chǎn)生不可預(yù)知的后果(如修改某個(gè)重要數(shù)據(jù)時(shí)),另外,它也沒(méi)有給線程任何清理現(xiàn)場(chǎng)的機(jī)會(huì)(如釋放內(nèi)存和鎖等)。

因此,停止線程可以,如上代碼所示,手寫(xiě)函數(shù)stop(),使其線程柔和的退出。

線程停止后,應(yīng)調(diào)用QThread::wait()函數(shù),它使的線程阻塞等待直到退出或超時(shí)。

貌似在Unix或Linux下編譯多線程應(yīng)用程序還必須在.pro文件中加入如下一行,它告訴qmake使用Qt庫(kù)中的線程版本。Windows上,Qt庫(kù)默認(rèn)就是線程的。

CONFIG += thread

介紹完了線程的創(chuàng)建,接下來(lái)走入正題了,多線程應(yīng)用程序的一個(gè)最普通的需求就是同步幾個(gè)線程。Qt提供了以下幾個(gè)類(lèi)來(lái)完成這一點(diǎn):QMutex、QMutexLocker、QSemphore、QWaitCondition。

當(dāng)然可能還包含QReadWriteLocker、QReadLocker、QWriteLocker,但線程同步是應(yīng)用很少,這里只做簡(jiǎn)單的講解!

QMutex、QMutexLocker

QMutex類(lèi)提供了一個(gè)保護(hù)一段臨界區(qū)代碼的方法,他每次只允許一個(gè)線程訪問(wèn)這段臨界區(qū)代碼。QMutex::lock()函數(shù)用來(lái)鎖住互斥量,如果互斥量處于解鎖狀態(tài),當(dāng)前線程就會(huì)立即抓住并鎖定它;否則當(dāng)前線程就會(huì)被阻塞,直到持有這個(gè)互斥量的線程對(duì)其解鎖。線程調(diào)用lock()函數(shù)后就會(huì)持有這個(gè)互斥量直到調(diào)用unlock()操作為止。QMutex還提供了一個(gè)tryLock()函數(shù),如果互斥量已被鎖定,就立即返回。

現(xiàn)在使用QMutex保護(hù)上面的線程類(lèi)的m_stop布爾變量,雖然沒(méi)啥用,但這里的目的只是為了演示下QMutex的用法~~

  1. //thread.h頭文件,添加互斥量對(duì)象  
  2. private:  
  3.     ...  
  4.     QMutex mutex;  
  5. };  
  6. void Thread::run()  
  7. {  
  8.     forever {  
  9.         mutex.lock();  
  10.         if (m_stop) {  
  11.             m_stop = false;  
  12.             mutex.unlock();  
  13.             break;  
  14.         }  
  15.         mutex.unlock();  
  16.         qDebug("vic.MINg!");  
  17.     }  
  18.     qDebug("end!");  
  19. }  
  20. void Thread::stop()  
  21. {  
  22.     mutex.lock();  
  23.     m_stop = true;  
  24.     mutex.unlock();  

在這里QMutex能夠完全完成互斥操作,但是有些情況下QMutex類(lèi)是無(wú)法某些特定的互斥操作的,下面舉個(gè)例子:

#p#

這里我們把void stop()函數(shù),重新定義下,讓他以布爾形式返回,實(shí)際也沒(méi)有啥用...只為示例的演示效果~~

  1. bool Thread::stop()  
  2. {  
  3.     m_stop = true;  
  4.     return m_stop;  

現(xiàn)在問(wèn)題出來(lái)了,如果要在stop()函數(shù)中使用mutex進(jìn)行互斥操作,但unlock()操作寫(xiě)在那里?unlock()操作卻不得不再return之后,從而導(dǎo)致unlock()操作永遠(yuǎn)也無(wú)法執(zhí)行...

Qt提供了QMutexLocker類(lèi)何以簡(jiǎn)化互斥量的處理,它在構(gòu)造函數(shù)中接受一個(gè)QMutex對(duì)象作為參數(shù)并將其鎖定,在析構(gòu)函數(shù)中解鎖這個(gè)互斥量。

這樣可以像下面這樣重新編寫(xiě)stop()函數(shù):

  1. bool Thread::stop()  
  2. {  
  3.     QMutexLocker locker(&mutex);  
  4.     m_stop = true;  
  5.     return m_stop;  

QReadWriteLocker、QReadLocker、QWriteLocker

下面是一段對(duì)QReadWriteLocker類(lèi)的對(duì)象進(jìn)行,讀寫(xiě)鎖的操作,比較簡(jiǎn)單,這里也不多做講解了,自己看吧 :)

  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.     ...  

QSemphore

Qt中的信號(hào)量是由QSemaphore類(lèi)提供的,信號(hào)量可以理解為互斥量功能的擴(kuò)展,互斥量只能鎖定一次而信號(hào)量可以獲取多次,它可以用來(lái)保護(hù)一定數(shù)量的同種資源。

acquire(n)函數(shù)用于獲取n個(gè)資源,當(dāng)沒(méi)有足夠的資源時(shí)調(diào)用者將被阻塞直到有足夠的可用資源。release(n)函數(shù)用于釋放n個(gè)資源。

QSemaphore類(lèi)還提供了一個(gè)tryAcquire(n)函數(shù),在沒(méi)有足夠的資源是該函數(shù)會(huì)立即返回。

一個(gè)典型的信號(hào)量應(yīng)用程序是在兩個(gè)線程間傳遞一定數(shù)量的數(shù)據(jù)(DataSize),而這兩個(gè)線程使用一定大小(BufferSize)的共享循環(huán)緩存。

  1. const int DataSize = 100000;  
  2. const int BufferSize = 4096;  
  3. char buffer[BufferSize]; 

生產(chǎn)者線程向緩存中寫(xiě)入數(shù)據(jù),直到它到達(dá)終點(diǎn),然后在起點(diǎn)重新開(kāi)始,覆蓋已經(jīng)存在的數(shù)據(jù)。消費(fèi)者線程讀取前者產(chǎn)生的數(shù)據(jù)。

生產(chǎn)者、消費(fèi)者實(shí)例中對(duì)同步的需求有兩處,如果生產(chǎn)者過(guò)快的產(chǎn)生數(shù)據(jù),將會(huì)覆蓋消費(fèi)者還沒(méi)有讀取的數(shù)據(jù),如果消費(fèi)者過(guò)快的讀取數(shù)據(jù),將越過(guò)生產(chǎn)者并且讀取到一些垃圾數(shù)據(jù)。

解決這個(gè)問(wèn)題的一個(gè)有效的方法是使用兩個(gè)信號(hào)量:

  1. QSemaphore freeSpace(BufferSize);  
  2. QSemaphore usedSpace(0); 

freeSpace信號(hào)量控制生產(chǎn)者可以填充數(shù)據(jù)的緩存部分。usedSpace信號(hào)量控制消費(fèi)者可以讀取的區(qū)域。這兩個(gè)信號(hào)量是互補(bǔ)的。其中freeSpace信號(hào)量被初始化為BufferSize(4096),表示程序一開(kāi)始有BufferSize個(gè)緩沖區(qū)單元可被填充,而信號(hào)量usedSpace被初始化為0,表示程序一開(kāi)始緩沖區(qū)中沒(méi)有數(shù)據(jù)可供讀取。

#p#

對(duì)于這個(gè)實(shí)例,每個(gè)字節(jié)就看作一個(gè)資源,實(shí)際應(yīng)用中常會(huì)在更大的單位上進(jìn)行操作,從而減小使用信號(hào)量帶來(lái)的開(kāi)銷(xiāo)。

  1. void Producer::run()  
  2. {  
  3.     for (int i = 0; i < DataSize; ++i) {  
  4.         freeSpace.acquire();  
  5.         buffer[i % BufferSize] = "MING"[uint(rand()) % 4];  
  6.         usedSpace.release();  
  7.     }  

在生產(chǎn)者中,我們從獲取一個(gè)“自由的”字節(jié)開(kāi)始。如果緩存被消費(fèi)者還沒(méi)有讀取的數(shù)據(jù)填滿,acquire()的調(diào)用就會(huì)阻塞,直到消費(fèi)者已經(jīng)開(kāi)始消耗這些數(shù)據(jù)為止。一旦我們已經(jīng)獲取了這個(gè)字節(jié),我們就用一些隨機(jī)數(shù)據(jù)("M"、"I"、"N"或"G")填充它并且把這個(gè)字節(jié)釋放為“使用的”,所以它可以被消費(fèi)者線程使用。

  1. void Consumer::run()  
  2. {  
  3.     for (int i = 0; i < DataSize; ++i) {  
  4.         usedSpace.acquire();  
  5.         cerr << buffer[i % BufferSize];  
  6.         freeSpace.release();  
  7.     }  
  8.     cerr << endl;  

在消費(fèi)者中,我們從獲取一個(gè)“使用的”字節(jié)開(kāi)始。如果緩存中沒(méi)有包含任何可讀的數(shù)據(jù),acquire()調(diào)用將會(huì)阻塞,直到生產(chǎn)者已經(jīng)產(chǎn)生一些數(shù)據(jù)。一旦我們已經(jīng)獲取了這個(gè)字節(jié),我們就打印它并且把這個(gè)字節(jié)釋放為“自由的”,使它可以被生產(chǎn)者使用來(lái)再次填充數(shù)據(jù)。

  1. int main()  
  2. {  
  3.     Producer producer;  
  4.     Consumer consumer;  
  5.     producer.start();  
  6.     consumer.start();  
  7.     producer.wait();  
  8.     consumer.wait();  
  9.     return 0;  

main()函數(shù)的功能比較簡(jiǎn)單,負(fù)責(zé)啟動(dòng)生產(chǎn)者和消費(fèi)者線程,然后等待其各自執(zhí)行完畢后自動(dòng)退出。

QWaitCondition

對(duì)生產(chǎn)者和消費(fèi)者問(wèn)題的另一個(gè)解決方法是使用QWaitCondition,它允許線程在一定條件下喚醒其他線程。其中wakeOne()函數(shù)在條件滿足時(shí)隨機(jī)喚醒一個(gè)等待線程,而wakeAll()函數(shù)則在條件滿足時(shí)喚醒所有等待線程
下面重寫(xiě)生產(chǎn)者和消費(fèi)者實(shí)例,以QMutex為等待條件,QWaitCondition允許一個(gè)線程在一定條件下喚醒其他線程

  1. const int DataSize = 100000;  
  2. const int BufferSize = 4096;  
  3. char buffer[BufferSize];  
  4. QWaitCondition bufferIsNotFull;  
  5. QWaitCondition bufferIsNotEmpty;  
  6. QMutex mutex;  
  7. int usedSpace = 0

在緩存之外,我們聲明了兩個(gè)QWaitCondition、一個(gè)QMutex和一個(gè)存儲(chǔ)了在緩存中有多少個(gè)“使用的”字節(jié)的變量。

  1. void Producer::run()  
  2. {  
  3.     for (int i = 0; i < DataSize; ++i) {  
  4.         mutex.lock();  
  5.         if (usedSpace == BufferSize)  
  6.             bufferIsNotFull.wait(&mutex);  
  7.         buffer[i % BufferSize] = "MING"[uint(rand()) % 4];  
  8.         ++usedSpace;  
  9.         bufferIsNotEmpty.wakeAll();  
  10.         mutex.unlock();  
  11.     }  

在生產(chǎn)者中,我們從檢查緩存是否充滿開(kāi)始。如果是充滿的,我們等待“緩存不是充滿的”條件。當(dāng)這個(gè)條件滿足時(shí),我們向緩存寫(xiě)入一個(gè)字節(jié),增加usedSpace,并且在喚醒任何等待這個(gè)“緩存不是空白的”條件變?yōu)檎娴?strong>線程。

for循環(huán)中的所有語(yǔ)句需要使用互斥量加以保護(hù),以保護(hù)其操作的原子性。

  1. bool wait ( QMutex * mutex, unsigned long time = ULONG_MAX ); 

這個(gè)函數(shù)做下說(shuō)明,該函數(shù)將互斥量解鎖并在此等待,它有兩個(gè)參數(shù),第一個(gè)參數(shù)為一個(gè)鎖定的互斥量,第二個(gè)參數(shù)為等待時(shí)間。如果作為第一個(gè)參數(shù)的互斥量在調(diào)用是不是鎖定的或出現(xiàn)遞歸鎖定的情況,wait()函數(shù)將立即返回。

調(diào)用wait()操作的線程使得作為參數(shù)的互斥量在調(diào)用前變?yōu)殒i定狀態(tài),然后自身被阻塞變成為等待狀態(tài)直到滿足以下條件:

其他線程調(diào)用了wakeOne()或者wakeAll()函數(shù),這種情況下將返回"true"值。

第二個(gè)參數(shù)time超時(shí)(以毫秒記時(shí)),該參數(shù)默認(rèn)情況是ULONG_MAX,表示永不超時(shí),這種情況下將返回"false"值。

wait()函數(shù)返回前會(huì)將互斥量參數(shù)重新設(shè)置為鎖定狀態(tài),從而保證從鎖定狀態(tài)到等待狀態(tài)的原則性轉(zhuǎn)換。

  1. void Consumer::run()  
  2. {  
  3.     forever {  
  4.         mutex.lock();  
  5.         if (usedSpace == 0)  
  6.             bufferIsNotEmpty.wait(&mutex);  
  7.         cerr << buffer[i % BufferSize];  
  8.         --usedSpace;  
  9.         bufferIsNotFull.wakeAll();  
  10.         mutex.unlock();  
  11.     }  
  12.     cerr << endl;  

消費(fèi)者做的和生產(chǎn)者正好相反,他等待“緩存不是空白的”條件并喚醒任何等待“緩存不是充滿的”的條件的線程。

main()函數(shù)與上面的基本相同,這個(gè)不再多說(shuō)。

在QThread類(lèi)的靜態(tài)函數(shù)currentThread(),可以返回當(dāng)前線程線程ID。在X11環(huán)境下,這個(gè)ID是一個(gè)unsigned long類(lèi)型的值。

小結(jié):關(guān)于 Qt 線程同步實(shí)例介紹的內(nèi)容介紹完了,希望本文對(duì)你有所幫助。

責(zé)任編輯:zhaolei 來(lái)源: 互聯(lián)網(wǎng)
相關(guān)推薦

2011-06-14 16:45:57

Qt 圖標(biāo)

2011-06-22 15:50:45

QT 線程

2011-08-29 10:22:48

QtWebkit 模塊HTML文檔

2011-06-14 09:46:11

Qt QThread 線程

2011-08-29 10:34:36

QTQWebKitJavaScript

2011-06-30 17:31:32

Qt 多線程 信號(hào)

2010-03-15 19:37:00

Java多線程同步

2011-08-25 15:21:02

Lua字符串

2010-03-17 15:34:09

Java線程同步引用

2009-10-12 13:19:14

VB.NET線程同步

2010-03-18 14:09:20

Java線程同步

2010-06-11 11:24:24

Mrtg教程

2011-06-22 16:18:23

QT 多線程 QSocket

2011-07-01 11:18:50

Qt 多線程

2022-08-17 06:25:19

偽共享多線程

2022-08-18 08:24:19

Mysql數(shù)據(jù)庫(kù)

2011-07-01 10:35:20

QT 多線程 TCP

2011-07-05 14:46:34

2011-06-27 16:07:49

Qt Designer

2011-06-21 09:33:49

Qt 啟動(dòng) 界面
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)