c11提供另外一種用於等待的同步機制,它可以阻塞乙個或者多個執行緒,直到收到另外乙個執行緒發出的通知或者超時,才會喚醒當前阻塞的執行緒。條件變數要和互斥量配合起來使用。
condition_variable,配合std::unique_lock進行wait操作。
condition_variable_any,和任意帶有lock、unlock語意 的mutex搭配使用,比較靈活,但是效率比condition_variable低。
條件變數的使用過程如下:
a.擁有條件變數的執行緒獲取互斥量。
b.迴圈檢查某個條件,如果條件不滿足,則阻塞執行緒直到滿足;如果條件滿足,則向下執行。
c.某個執行緒滿足條件並執行完成之後,呼叫notify_one或者notify_all來喚醒乙個或者多個執行緒。
可以用條件變數來實現乙個同步佇列,同步佇列作為乙個執行緒安全的資料共享區,經常用於執行緒之間的讀取,比如半同步半非同步執行緒池的同步佇列。
#include #include#include
#include
#include
#include
template
class
syncqueue
void put(const t &t)
m_queue.push_back(t);
m_notempty.notify_one();
}void take(const t &t)
t =m_queue.front();
m_queue.pop_front(t);
m_notfull.notify_one();
}bool
empty()
bool
full()
size_t size()
private
:
bool isfull() const
bool isempty() const
private
: std::list
m_queue; //
緩衝區 std::mutex m_mutex; //
互斥量 std::condition_variable_any m_notempty; //
不為空的條件變數
std::condition_variable_any m_notfull; //
沒有滿的條件變數
int m_maxsize; //
同步佇列最大容量
};
這個佇列中,沒有滿的情況下可以插入資料,如果滿了,則會呼叫m_notfull阻塞執行緒等待,等待消費執行緒取出資料之後發出乙個未滿的通知,然後前面阻塞的執行緒會被喚醒繼續往下執行;如果隊列為空,不能取出資料,呼叫m_notempty來阻塞當前執行緒,等待插入資料的執行緒插入資料發出不為空的通知,喚醒被阻塞的執行緒,往下執行讀出資料。
條件變數的wait方法還有個過載方法,可以接受乙個條件。
std::lock_guardlocker(m_mutex);while
(isfull())
可以寫為這樣:
std::lock_guardlocker(m_mutex);m_notfull.wait(locker, [
this]);
兩種寫法都一樣,後者**更加簡潔,條件變數先檢查判斷式是否滿足條件,如果滿足,重新獲取mutex,結束wait,繼續往下執行;如果不滿足條件,則釋放mutex,將執行緒置為waiting狀態,繼續等待。
需要注意的是,wait函式會釋放掉mutex,而lock_guard還擁有mutex,他只在出了作用域之後才會釋放掉mutex,所以這時並不會釋放,但是執行wait會提前釋放,而在wait提前釋放掉鎖之後,會處於等待狀態,在notify_one/all喚醒之後,會先獲取mutex,相當於之前的mutex又獲取到了,所以在出作用域的時候,lock_guard釋放鎖不會產生問題。
在這種情況下,如果用unique_lock語意更準確,因為unique_lock不像lock_guard一樣只能在析構的時候才能釋放鎖,它可以隨時釋放鎖,在wait的時候讓uniq_lock釋放鎖,語意更加準確。
上述例子中,可以用unique_lock來替換掉lock_guard,condition_variable來替換掉condition_variable_any,會使**更加清晰,效率也更高。
除了wait還可以使用超時等待函式std::condition_variable::wait_for和std::condition_variable::wait_until。
與 std::condition_variable::wait() 類似,不過 wait_for 可以指定乙個時間段,在當前執行緒收到通知或者指定的時間 rel_time 超時之前,該執行緒都會處於阻塞狀態。而一旦超時或者收到了其他執行緒的通知,wait_for 返回,剩下的處理步驟和 wait() 類似。
與 std::condition_variable::wait_for 類似,但是 wait_until 可以指定乙個時間點,在當前執行緒收到通知或者指定的時間點 abs_time 超時之前,該執行緒都會處於阻塞狀態。而一旦超時或者收到了其他執行緒的通知,wait_until 返回,剩下的處理步驟和 wait_for() 類似。
//condition_variable::wait_for example
#include //
std::cout
#include //
std::thread
#include //
std::chrono::seconds
#include //
std::mutex, std::unique_lock
#include //
std::condition_variable, std::cv_status
std::condition_variable cv;
intvalue;
void
read_value()
intmain ()
std::cout
<< "
you entered:
"<< value << '\n'
; //等待th執行緒執行完
th.join();
return0;
}
如果用wait_until,只需要將條件改為時間點即可:
while (cv.wait_for(lck,std::chrono::seconds(1))==std::cv_status::timeout)while (cv.wait_until(lck, std::chrono::system_clock::now() +std::chrono::seconds(1)) == std::cv_status::timeout)
C 11多執行緒學習 條件變數
c 11中的std condition variable 首先,舉個例子 在應用程式中有4個程序thread1,thread2,thread3和thread4,有乙個int型別的全域性變數icount。icount初始化為0,thread1和thread2的功能是對icount的加1,thread3...
3執行緒同步 C 11中的條件變數
在c11標頭檔案中包含了如下內容 cv status 條件等待結果的列舉。condition variable 條件變數的主要類,用於實現執行緒同步。condition variable any 是對condition variable的擴充套件,condition variable只能等待uniq...
C 11 多執行緒同步 互斥鎖 條件變數
在多執行緒程式中,執行緒同步 多個執行緒訪問乙個資源保證順序 是乙個非常重要的問題,linux下常見的執行緒同步的方法有下面幾種 這篇部落格只介紹互斥量和條件變數的使用。通常情況下,互斥鎖和條件變數是配合使用的,互斥鎖用於短期鎖定,主要保證執行緒對臨界區的進入 條件變數用於執行緒長期等待,在wait...