C 條件變數使用詳解

2021-09-23 16:58:11 字數 3780 閱讀 6188

目錄

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