目錄
condition_variable介紹
細節說明
wait/wait_for說明
wait()成員函式
wait_for()成員函式
notify_all/notify_one
虛假喚醒
條件變數使用
在c++11中,我們可以使用條件變數(condition_variable)實現多個執行緒間的同步操作;當條件不滿足時,相關執行緒被一直阻塞,直到某種條件出現,這些執行緒才會被喚醒。
其主要成員函式如下:
條件變數是利用執行緒間共享的全域性變數進行同步的一種機制,主要包括兩個動作:
為了防止競爭,條件變數的使用總是和乙個互斥鎖結合在一起;通常情況下這個鎖是std::mutex,並且管理這個鎖 只能是 std::unique_lockstd::mutex raii模板類。
上面提到的兩個步驟,分別是使用以下兩個方法實現:
在條件變數中只能使用std::unique_lock< std::mutex >說明
unique_lock和lock_guard都是管理鎖的輔助類工具,都是raii風格;它們是在定義時獲得鎖,在析構時釋放鎖。它們的主要區別在於unique_lock鎖機制更加靈活,可以再需要的時候進行lock或者unlock呼叫,不非得是析構或者構造時。它們的區別可以通過成員函式就可以一目了然。在這裡插入描述
執行緒的阻塞是通過成員函式wait()/wait_for()/wait_until()函式實現的。這裡主要說明前面兩個函式:
函式宣告如下:
void wait( std::unique_lock& lock );
//predicate 謂詞函式,可以普通函式或者lambda表示式
template
void wait( std::unique_lock& lock, predicate pred );
wait 導致當前執行緒阻塞直至條件變數被通知,或虛假喚醒發生,可選地迴圈直至滿足某謂詞。
函式宣告如下:
template
std::cv_status wait_for( std::unique_lock& lock,
const std::chrono::duration& rel_time);
template
bool wait_for( std::unique_lock& lock,
const std::chrono::duration& rel_time,
predicate pred);
wait_for 導致當前執行緒阻塞直至條件變數被通知,或虛假喚醒發生,或者超時返回。
返回值說明:
若經過 rel_time 所指定的關聯時限則為 std::cv_status::timeout ,否則為 std::cv_status::no_timeout 。
若經過 rel_time 時限後謂詞 pred 仍求值為 false 則為 false ,否則為 true 。
以上兩個型別的wait函式都在會阻塞時,自動釋放鎖許可權,即呼叫unique_lock的成員函式unlock(),以便其他執行緒能有機會獲得鎖。這就是條件變數只能和unique_lock一起使用的原因,否則當前執行緒一直占有鎖,執行緒被阻塞。
notify函式宣告如下:
void notify_one() noexcept;
若任何執行緒在 *this 上等待,則呼叫 notify_one 會解阻塞(喚醒)等待執行緒之一。
void notify_all() noexcept;
若任何執行緒在 *this 上等待,則解阻塞(喚醒)全部等待執行緒。
在正常情況下,wait型別函式返回時要不是因為被喚醒,要不是因為超時才返回,但是在實際中發現,因此作業系統的原因,wait型別在不滿足條件時,它也會返回,這就導致了虛假喚醒。因此,我們一般都是使用帶有謂詞引數的wait函式,因為這種(***, predicate pred )型別的函式等價於:
while (!pred()) //while迴圈,解決了虛假喚醒的問題
原因說明如下:
假設系統不存在虛假喚醒的時,**形式如下:
if (不滿足***條件)
//其他**
...
正確的使用方式,使用while語句解決:
while (!(***條件) )
//其他**
....
在這裡,我們使用條件變數,解決生產者-消費者問題,該問題主要描述如下:
生產者-消費者問題,也稱有限緩衝問題,是乙個多程序/執行緒同步問題的經典案例。該問題描述了共享固定大小緩衝區的兩個程序/執行緒——即所謂的「生產者」和「消費者」,在實際執行時會發生的問題。
生產者的主要作用是生成一定量的資料放到緩衝區中,然後重複此過程。與此同時,費者也在緩衝區消耗這些資料。該問題的關鍵就是要保證生產者不會在緩衝區滿時加入資料,消費者也不會在緩衝區中空時消耗資料。
要解決該問題,就必須讓生產者在緩衝區滿時休眠(要麼乾脆就放棄資料),等到下次消費者消耗緩衝區中的資料的時候,生產者才能被喚醒,開始往緩衝區新增資料。
同樣,也可以讓消費者在緩衝區空時進入休眠,等到生產者往緩衝區新增資料之後,再喚醒消費者。
生產者-消費者**如下:
std::mutex g_cvmutex;
std::condition_variable g_cv;
//快取區
std::dequeg_data_deque;
//快取區最大數目
const int max_num = 30;
//資料
int g_next_index = 0;
//生產者,消費者執行緒個數
const int producer_thread_num = 3;
const int consumer_thread_num = 3;
void producer_thread(int thread_id)
); g_next_index++;
g_data_deque.push_back(g_next_index);
std::cout <
std::cout <
//喚醒其他執行緒
g_cv.notify_all();
//自動釋放鎖
}}void consumer_thread(int thread_id)
); //互斥操作,訊息資料
int data = g_data_deque.front();
g_data_deque.pop_front();
std::cout <
std::cout <
//喚醒其他執行緒
g_cv.notify_all();
//自動釋放鎖
}}int main()
for (int i = 0; i
for (int i = 0; i
for (int i = 0; i
return 0;
}
執行結果:
詳解條件變數
一年多過去啦,一段時間沒有posix多執行緒的東西,又忘記的差不多略,我打記性咋這麼差,絲毫記不起來怎麼用啦,還是不如爛筆頭啊。lock wait unlock.在呼叫pthread cond wait cond,mutex 時的執行順序是這樣的 1.首先獲取外面的mutex,然後當前wait pu...
C 條件變數
1.作用 在c 11中,我們可以使用條件變數 std condition variable 實現多個執行緒間的同步操作 當條件不滿足時,相關執行緒被一直阻塞,並釋放cpu,直到某種條件出現,這些執行緒才會被喚醒。條件變數需要和互斥量 鎖 一起搭配使用。用在多執行緒中。執行緒a 等待乙個條件滿足 執行...
C 條件變數
condition variable 類是同步原語,能用於阻塞乙個執行緒,或同時阻塞多個執行緒,直至另一線程修改共享變數 條件 並通知 condition variable 有意修改變數的執行緒必須 獲得 std mutex 常通過 std lock guard 在保有鎖時進行修改 在 std co...