一段简单的示例代码
#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线程,仍然可以观察到相同序列,基本证明猜想正确。
多消费者多生产者的情况也完全符合预期。不过经过一番尝试,并没有模拟出虚假唤醒的情况,有待进一步考察。
网友评论