当某个线程持有这把锁的时候(就是所谓的加锁),那么这个线程是独占全部的资源,这里的资源指的是执行的权限,其余要抢夺资源的线程都不得不等待。在不少状况下,这都容易适用,可是有些状况下,却会产生一些异常状况。ios
在生产消费者模型当中,确定都会用到互斥锁的机制的,当生产者往队列中放数据的瞬间,消费者是不能取数据的,那这时候可能会遇见一个问题,若是生成者由于某些缘由,放数据过慢,可是消费者取数据很快,当队列中没有数据了,消费者还去取的话,就会发生异常状况。有些人可能会说,加个条件判断一下队列是否为空不就能够了。编程
这个确定是固然能够的,可是在队列依旧没有数据的这一段时间,是要不断的循环判断这个条件,CPU确定是会飙升的,浪费了不少没必要要的资源。多线程
这时候咱们设想,可否设计这样的一种机制,若是在队列没有数据的时候,消费者线程能一直阻塞在那里,等待着别人给它唤醒,在生产者往队列中放入数据的时候通知一下这个等待线程,唤醒它,告诉它能够来取数据了。框架
因而多线程中的条件变量就横空出世!函数
条件变量是多线程数据同步的一种操做,无论是用哪一种框架,哪一种语言实现多线程的功能,条件变量都是不得不考虑的一种状况。C++中提供了#include <condition_variable>头文件,里面就包含了条件变量的相关类。其中有两个很是重要的接口,wait()和notify_one(),wait()可让线程陷入休眠状态,意思就是不干活了,notify_one()就是唤醒真正休眠状态的线程,开始干活了。固然还有notify_all()这个接口,顾名思义,就是通知全部正在等待的线程,起来干活了。优化
如下是代码的实现部分this
#include <iostream> #include <deque> #include <thread> #include <mutex> #include <condition_variable> using namespace std; deque<int> q; mutex mt; condition_variable cond; void thread_producer() { int count = 10; while (count > 0) { unique_lock<mutex> unique(mt); q.push_front(count); unique.unlock(); cout << "producer a value: " << count << endl; cond.notify_one(); this_thread::sleep_for(chrono::seconds(1)); count--; } } void thread_consumer() { int data = 0; while (data != 1) { unique_lock<mutex> unique(mt); while (q.empty()) cond.wait(unique); data = q.back(); q.pop_back(); cout << "consumer a value: " << data << endl; unique.unlock(); } } int main() { thread t1(thread_consumer); thread t2(thread_producer); t1.join(); t2.join(); return 0; }
生产者:首先生产者利用unique_lock来加锁,而后将生产的数据放入队列,打印,解锁,一旦解锁以后,消费者得到了执行机会。spa
消费者:另外一方面消费者就会经过unique_lock得到控制权,也就是得到锁,而后判断队列为空的话就一直盗用wait()函数阻塞在那里,等待其余线程来唤醒它。而阻塞该线程时,该函数会自动解锁,容许其余线程执行。线程
生产者:再次回到生产者这里,生产者线程利用利用条件变量cond.notify_one()来通知阻塞的线程起来干活了。设计
消费者:阻塞在那里的消费者线程一旦获得notify唤醒,该函数取消阻塞并获取锁,而后取出队列中的数据,并打印,最后解锁。
生产者:再次回到生产者,而后生产者休眠1秒,这里休眠是为了模拟生产者生产慢的状况,实际开发的时候不要去休眠。最后减一,进入下一次生产。
以上就是利用条件变量来实现生产消费者模型,这个会大大下降CPU的占有率,固然代价就是编程稍微有点麻烦,但与这优化程序来比,这确定是值的。
更多精彩内容,请关注同名公众:一点笔记alittle