線程的互斥和同步(7)- Qt的條件變量QWaitCondition

QWaitCondition 提供了一個用於同步線程的條件變量。它允許一個線程後告訴其他的線程已經滿足了某種條件;一個或多個線程可以阻塞等待 QWaitCondition 來使用 wakeOne()wakeAll() 設置條件。使用 wakeOne() 喚醒一個隨機選擇的線程或者 wakeAll() 喚醒全部等待的線程。


下面是 QWaitCondition 類中,常用的函數介紹:

bool wait (QMutex *lockedMutex, unsigned long time = ULONG_MAX)

釋放鎖資源等待等待條件。lockedMutex 初始化必須是上鎖的狀態,根據調用的線程。如果 lockedMutex 沒有上鎖,他的行爲是未知的。如果 lockedMutex 是可遞歸的鎖,則該函數立即返回。 lockedMutex 將被解鎖,調用線程將被阻塞,直到滿足以下任一條件:

  • 另一個線程使用 wakeOne()wakeAll() 發出信號。在這種情況下,這個函數將返回true
  • 時間毫秒已經過去。如果時間是ULONG_MAX(默認值),那麼等待將永遠不會超時(必須通知事件)。如果等待超時,這個函數將返回 false

lockedMutex 將返回到相同 locked 狀態。此函數提供了允許原子性的從鎖定狀態轉換到等待狀態。。

void wakeOne () 和 void wakeAll ()

表示喚醒一個或多個線程。喚醒的順序是根據操作系統的調度決定的。


上一篇文章我們介紹了使用信號量實現 生產者-消費者 例子
線程的互斥和同步(6)- Qt的信號量QSemaphore
條件變量是一個針對信號量的可替代選擇,本篇文章將使用條件變量替代信號量,實現同樣的效果:

數據定義,頭文件:

#include <QSemaphore>
#include <QWaitCondition>
#include <QMutex>
#include <atomic>

extern "C" int g_data[20];
extern "C" int g_nStartIndex;
extern "C" int g_nEndIndex;
extern "C" int g_nCurrentCreated;
extern "C" QWaitCondition g_notFullCondition;	// 未滿條件變量
extern "C" QWaitCondition g_notEmptyCondition;	// 未空條件變量
extern "C" QMutex g_mutex;

cpp文件

int g_data[20] = {-1};
int g_nStartIndex = 0;
int g_nEndIndex = 0;
int g_nCurrentCreated = 0;
QWaitCondition g_notFullCondition;
QWaitCondition g_notEmptyCondition;
QMutex g_mutex;

生產者實現:

void ProducerThread::run(void)
{
    while (1)
    {
        g_mutex.lock();
        // 當緩存滿了的時候,等待是否有消費者消費
        if (g_nCurrentCreated == 20)
            g_notFullCondition.wait(&g_mutex);
        g_mutex.unlock();

        // 生產數據
        g_data[g_nEndIndex] = number;
        std::cout << "Created Data: " << number++ \
                  << ", Index is " << g_nEndIndex << std::endl;

        g_nEndIndex++;
        if (g_nEndIndex == 20)
            g_nEndIndex = 0;

        ::Sleep(100);

        g_mutex.lock();
        g_nCurrentCreated++;
        // 喚醒消費者
        g_notEmptyCondition.wakeAll();
        g_mutex.unlock();
    }
}

消費者實現:

void ConsumerThread::run(void)
{
    while (1)
    {
        g_mutex.lock();
        // 等待
        if (g_nCurrentCreated == 0)
            g_notEmptyCondition.wait(&g_mutex);
        g_mutex.unlock();

        // 消費數據
        std::cout << "Read Value: " << g_data[g_nStartIndex] \
                  << ", Index is " << g_nStartIndex << std::endl;

        g_nStartIndex++;
        if (g_nStartIndex == 20)
            g_nStartIndex = 0;

        ::Sleep(2000);

        // 釋放資源
        g_mutex.lock();
        g_nCurrentCreated--;
        // 喚醒生產者生產
        g_notFullCondition.wakeAll();
        g_mutex.unlock();
    }
}

程序運行結果:
Created Data: 0, Index is 0
Created Data: 1, Index is 1
Read Value: 0, Index is 0
Created Data: 2, Index is 2
Created Data: 3, Index is 3
Created Data: 4, Index is 4
Created Data: 5, Index is 5
Created Data: 6, Index is 6
Created Data: 7, Index is 7
Created Data: 8, Index is 8
Created Data: 9, Index is 9
Created Data: 10, Index is 10
Created Data: 11, Index is 11
Created Data: 12, Index is 12
Created Data: 13, Index is 13
Created Data: 14, Index is 14
Created Data: 15, Index is 15
Created Data: 16, Index is 16
Created Data: 17, Index is 17
Created Data: 18, Index is 18
Created Data: 19, Index is 19
Read Value: 1, Index is 1
Created Data: 20, Index is 0
Read Value: 2, Index is 2
Created Data: 21, Index is 1
Read Value: 3, Index is 3
Created Data: 22, Index is 2
Read Value: 4, Index is 4
Created Data: 23, Index is 3


作者:douzhq
個人博客主頁:不會飛的紙飛機
文章同步頁(可下載完整代碼):線程的互斥和同步(6)- Qt的條件變量QWaitCondition

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章