http://mobile.51cto.com/symbian-272643_2.htm
對於這個執行個體,每個位元組就看作一個資源,實際應用中常會在更大的單位上進行操作,從而減小使用訊號量帶來的開銷。
- void Producer::run()
- {
- for (int i = 0; i < DataSize; ++i) {
- freeSpace.acquire();
- buffer[i % BufferSize] = "MING"[uint(rand()) % 4];
- usedSpace.release();
- }
- }
在生產者中,我們從擷取一個“自由的”位元組開始。如果緩衝被消費者還沒有讀取的資料填滿,acquire()的調用就會阻塞,直到消費者已經開始消耗這些資料為止。一旦我們已經擷取了這個位元組,我們就用一些隨機資料("M"、"I"、"N"或"G")填充它並且把這個位元組釋放為“使用的”,所以它可以被消費者線程使用。
- void Consumer::run()
- {
- for (int i = 0; i < DataSize; ++i) {
- usedSpace.acquire();
- cerr << buffer[i % BufferSize];
- freeSpace.release();
- }
- cerr << endl;
- }
在消費者中,我們從擷取一個“使用的”位元組開始。如果緩衝中沒有包含任何可讀的資料,acquire()調用將會阻塞,直到生產者已經產生一些資料。一旦我們已經擷取了這個位元組,我們就列印它並且把這個位元組釋放為“自由的”,使它可以被生產者使用來再次填充資料。
- int main()
- {
- Producer producer;
- Consumer consumer;
- producer.start();
- consumer.start();
- producer.wait();
- consumer.wait();
- return 0;
- }
main()函數的功能比較簡單,負責啟動生產者和消費者線程,然後等待其各自執行完畢後自動結束。
QWaitCondition
對生產者和消費者問題的另一個解決方案是使用QWaitCondition,它允許線程在一定條件下喚醒其他線程。其中wakeOne()函數在條件滿足時隨機喚醒一個等待線程,而wakeAll()函數則在條件滿足時喚醒所有等待線程。
下面重寫生產者和消費者執行個體,以QMutex為等待條件,QWaitCondition允許一個線程在一定條件下喚醒其他線程。
- const int DataSize = 100000;
- const int BufferSize = 4096;
- char buffer[BufferSize];
- QWaitCondition bufferIsNotFull;
- QWaitCondition bufferIsNotEmpty;
- QMutex mutex;
- int usedSpace = 0;
在緩衝之外,我們聲明了兩個QWaitCondition、一個QMutex和一個儲存了在緩衝中有多少個“使用的”位元組的變數。
- void Producer::run()
- {
- for (int i = 0; i < DataSize; ++i) {
- mutex.lock();
- if (usedSpace == BufferSize)
- bufferIsNotFull.wait(&mutex);
- buffer[i % BufferSize] = "MING"[uint(rand()) % 4];
- ++usedSpace;
- bufferIsNotEmpty.wakeAll();
- mutex.unlock();
- }
- }
在生產者中,我們從檢查緩衝是否充滿開始。如果是充滿的,我們等待“緩衝不是充滿的”條件。當這個條件滿足時,我們向緩衝寫入一個位元組,增加usedSpace,並且在喚醒任何等待這個“緩衝不是空白的”條件變為真的線程。
for迴圈中的所有語句需要使用互斥量加以保護,以保護其操作的原子性。
- bool wait ( QMutex * mutex, unsigned long time = ULONG_MAX );
這個函數做下說明,該函數將互斥量解鎖並在此等待,它有兩個參數,第一個參數為一個鎖定的互斥量,第二個參數為等待時間。如果作為第一個參數的互斥量在調用是不是鎖定的或出現遞迴鎖定的情況,wait()函數將立即返回。
調用wait()操作的線程使得作為參數的互斥量在調用前變為鎖定狀態,然後自身被阻塞變成為等待狀態直到滿足以下條件:
其他線程調用了wakeOne()或者wakeAll()函數,這種情況下將返回"true"值。
第二個參數time逾時(以毫秒記時),該參數預設情況是ULONG_MAX,表示永不逾時,這種情況下將返回"false"值。
wait()函數返回前會將互斥量參數重新設定為鎖定狀態,從而保證從鎖定狀態到等待狀態的原則性轉換。
- void Consumer::run()
- {
- forever {
- mutex.lock();
- if (usedSpace == 0)
- bufferIsNotEmpty.wait(&mutex);
- cerr << buffer[i % BufferSize];
- --usedSpace;
- bufferIsNotFull.wakeAll();
- mutex.unlock();
- }
- cerr << endl;
- }
消費者做的和生產者正好相反,他等待“緩衝不是空白的”條件並喚醒任何等待“緩衝不是充滿的”的條件的線程。
main()函數與上面的基本相同,這個不再多說。
在QThread類的靜態函數currentThread(),可以返回當前線程的線程ID。在X11環境下,這個ID是一個unsigned long類型的值。
小結:關於 Qt 線程同步執行個體介紹的內容介紹完了,希望本文對你有所協助。