ACE線程管理機制-併發控制(3)

ACE Condition類屬

ACE Condition類屬(條件變量)提供風格與互斥體、讀者/作者鎖和計數信號量不同的鎖定機制。當持有鎖的線程在臨界區執行代碼時,這三種機制讓協作線程進行等待。相反,條件變量通常被一個線程用於使自己等待,直到一個涉及共享數據的條件表達式到達特定的狀態。當另外的協作線程指示共享數據的狀態已發生變化,調度器就喚醒一個在該條件變量上掛起的線程。於是新喚醒的線程重新對它的條件表達式進行求值,如果共享數據已到達合適狀態,就恢復處理。

ACE線程庫提供一個叫作Condition的類來可移植地在C++包裝類中實現條件變量語義。定義方式如下:
ACE_Thread_Mutex mutex;
ACE_Condition<ACE_Thread_Mutex> cond(mutex);

該對象有兩個常用方法。

  1. signal()
    向使用該條件變量的其它線程發送滿足條件信號。
  2. wait()
    查詢是否滿足條件,如果滿足,則繼續往下執行;如果不滿足條件,主線程就等待在此條件變量上。條件變量隨即自動釋放互斥體,並使主線程進入睡眠。

條件變量總是與互斥體一起使用。這是一種可如下描述的一般模式:

while( expression NOT TRUE ) wait on condition variable;

條件變量不是用於互斥,往往用於線程間的協作,下面例子演示了通過條件變量實現線程協作。

#include "ace/Thread.h"
#include "ace/Synch.h"

#include <iostream>
using namespace std;

ACE_Thread_Mutex mutex;
ACE_Condition<ACE_Thread_Mutex> cond(mutex);

void* worker(void *arg)
{
    ACE_OS::sleep(2);        //保證eater線程的cond.wait()在worker線程的cond.signal()先執行
    mutex.acquire();
    ACE_OS::sleep(1);
    cout<<endl<<"produce"<<endl;
    cond.signal();
    mutex.release();
    return NULL;
}

void* eater(void *arg)
{
    mutex.acquire();
    cond.wait();
    cout<<endl<<"eat"<<endl;
    mutex.release();
    return NULL;
}

int main(int argc, char *argv[])
{
    ACE_Thread::spawn((ACE_THR_FUNC)worker);
    ACE_OS::sleep(1);
    ACE_Thread::spawn((ACE_THR_FUNC)eater);

    while(true)
        ACE_OS::sleep(10);

    return 0;
}

這個例子中,首先創建了一個生產者線程worker和一個消費者線程eater,消費者線程執行比生產者快,兩個線程不加限制併發執行會導致先消費,後生產的情況(只是加互斥鎖也不能很好的解決,以爲無法保證生產者一定先獲得互斥體)。所以這裏通過條件變量的通知方式保證線程的順序執行:

  1. 消費者線程獲取互斥體,等待條件滿足(生產者生產了食品)。同時釋放互斥體,進入休眠狀態。
  2. 生產者獲取互斥體(雖然是消費者先獲取的互斥體,但消費者調用的wait函數會釋放消費者的互斥體),生產商品後,通過條件變量發送信號(調用signal函數)通知消費者生產完成,結束生產過程,釋放互斥體。
  3. 消費者收到信號後,重新獲取互斥體,完成消費過程。

     

使用條件變量的注意事項:

  1. 條件變量必須和互斥體一起使用,也就是說使用前必須加鎖(調用互斥體acquire函數),使用完後需釋放互斥體。

條件變量中的wait()和signal()成對使用的話,必須保證wait()函數在signal()之前執行,這樣才能保證wait()能收到條件滿足通知,不至於一直等待下去,形成死鎖(worker線程中的第一句話就是起的這個作用)。

發佈了9 篇原創文章 · 獲贊 2 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章