条件变量(一)

互斥器mutex用来排他性的访问共享数据,他不是等待原语。若要等待某个条件成立,我们应该使用条件变量(condition variable)。条件变量顾名思义就是一个或多个线程等待某个布尔表达式为真,即等待别的线程唤醒它。

条件变量只有一种使用方式,wait端:

1、必须与Mutex一起使用,以保护布尔表达式的读写收到保护。

2、Mutex上锁后才能调用wait()等待。

3、把wait()放到 while循环内,而不是if语句块内。否则会导致假唤醒。

对于条件变量,我的简单理解就是消费者和生产者:notify一段为生产者,告诉wait端有元素可以消费了。我在项目中最长遇到的就是将其用到BlockingQueue中。下面是简单的实现:

生产者, 将元素去出队列:

1 void enqueue(T t)
2 {
3      std::lock_guard<std::mutex> lock(m);
4      q.push_back(t);
5      c.notify_one();
6 }

消费者,将T value放入队列:

 1 T dequeue(T &value)
 2 {
 3     std::unique_lock<std::mutex> lock(m);
 4     while (q.empty()) {     //必须使用循环,必须在判断后再wait()
 5         c.wait();
 6     }
 7     value = q.front();
 8     q.pop();
 9     return value;
10 }

第五行代码c.wait()会把线程投入睡眠,并释放线程持有的互斥锁,当wait()返回时,该再次上锁,该线程再次持有该互斥锁。(这个怎么做到的?释放互斥锁,然后睡眠期间,该锁不会被别的线程持有吗?)

注意:一定要使用循环判断queue是否有元素可用,才调能用c.wait()。不然可能产生假唤醒。因为notify_one(调用的是pthread_cond_signal)或者notify_all(调用的是pthread_cond_broadcast)都只能唤醒正在wait()的线程,这就是所谓的边沿触发。 

注:本文参考http://www.cppblog.com/Solstice/archive/2015/10/30/203094.html

原文地址:https://www.cnblogs.com/howo/p/8552916.html