一段簡單的示例代碼
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
int i = 0;
std::mutex mtx;
std::condition_variable condition_in, condition_out;
void in(int id)
{
while (true)
{
//(1)
std::unique_lock<std::mutex> in(mtx);
condition_in.wait(in, [id](){
std::cout << "condition_in.wait id:" << id << std::endl;
return i < 5;
});
std::cout << "thread id:"<<id<<"# "<<"===>"<<++i<<std::endl;
//(2)
condition_out.notify_one();
//(3)
}
}
void out(int id)
{
while (true)
{
std::unique_lock<std::mutex> in(mtx);
condition_out.wait(in, [id](){
std::cout << "condition_out.wait id: " << id <<std::endl;
return i > 1;
});
i -= 2;
std::cout << "thread id:" << id<<"# "<<"===>" <<i << std::endl;
condition_in.notify_one();
}
}
void main()
{
std::thread t1(in,0);
std::thread t2(out,1);
//std::thread t3(out,2);
//std::thread t4(out,3);
//std::thread t5(out,4);
t1.join();
}
std::unique_lock
std::unique_lock 是一個使用RAII機制來管理 std::mutex 的一個類,相比于 std::lock_guard 有更靈活的方式,但會比 std::lock_guard 使用更多的空間。
Member functions
Locking/unlocking
lock
try_lock
try_lock_for
try_lock_until
unlock
Modifiers
operator= (Move-assign unique_lock)
swap
release
Observers
owns_lock
operator bool (Return whether it owns a lock)
mutex
運行結果
單消費者單生產者
condition_in.wait id:0
thread id:0# ===>1
condition_out.wait id: 1
condition_in.wait id:0
thread id:0# ===>2
condition_in.wait id:0
thread id:0# ===>3
condition_out.wait id: 1
thread id:1# ===>1
condition_in.wait id:0
thread id:0# ===>2
condition_out.wait id: 1
thread id:1# ===>0
condition_in.wait id:0
thread id:0# ===>1
condition_out.wait id: 1
condition_in.wait id:0
thread id:0# ===>2
condition_in.wait id:0
thread id:0# ===>3
condition_out.wait id: 1
thread id:1# ===>1
condition_in.wait id:0
thread id:0# ===>2
condition_out.wait id: 1
thread id:1# ===>0
結果大致如預期,但是通過觀察發現產品的個數總是以0->1->2->3->1->2->0的規律變化,按理說每次產品增加到2之后喚醒消費者線程應該就會將2個產品取走了。通過分析輸出日志,應該是因為被condition阻塞的線程從喚醒到重新上鎖的時間要長于 std::unique_lock<std::mutex> 鎖爭用時直接上鎖的時間。另外,啟動消費者和生產者線程的先后順序也會影響剛開始的輸出序列,但整體的變化規律不會變。在(1)處插入
if(i > 1)
然后先啟動t2,再啟動t1線程,仍然可以觀察到相同序列,基本證明猜想正確。
多消費者多生產者的情況也完全符合預期。不過經過一番嘗試,并沒有模擬出虛假喚醒的情況,有待進一步考察。