C++11多线程编程——生产消费者模型之条件变量

Posted 一点笔记alittle

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++11多线程编程——生产消费者模型之条件变量相关的知识,希望对你有一定的参考价值。

当某个线程持有这把锁的时候(就是所谓的加锁),那么这个线程是独占所有的资源,这里的资源指的是执行的权限,其他要抢夺资源的线程都不得不等待。在很多情况下,这都容易适用,但是有些情况下,却会产生一些异常情况。
在生产消费者模型当中,肯定都会用到互斥锁的机制的,当生产者往队列中放数据的瞬间,消费者是不能取数据的,那这时候可能会碰见一个问题,如果生成者因为某些原因,放数据过慢,但是消费者取数据很快,当队列中没有数据了,消费者还去取的话,就会发生异常情况。有些人可能会说,加个条件判断一下队列是否为空不就可以了。
这个肯定是当然可以的,但是在队列依旧没有数据的这一段时间,是要不断的循环判断这个条件,CPU肯定是会飙升的,浪费了很多不必要的资源。
这时候我们设想,能否设计这样的一种机制,如果在队列没有数据的时候,消费者线程能一直阻塞在那里,等待着别人给它唤醒,在生产者往队列中放入数据的时候通知一下这个等待线程,唤醒它,告诉它可以来取数据了。
于是多线程中的条件变量就横空出世!

条件变量是多线程数据同步的一种操作,不管是用哪种框架,哪种语言实现多线程的功能,条件变量都是不得不考虑的一种情况。C++中提供了#include <condition_variable>头文件,里面就包含了条件变量的相关类。其中有两个非常重要的接口,wait()和notify_one(),wait()可以让线程陷入休眠状态,意思就是不干活了,notify_one()就是唤醒真正休眠状态的线程,开始干活了。当然还有notify_all()这个接口,顾名思义,就是通知所有正在等待的线程,起来干活了。

以下是代码的实现部分
#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来加锁,然后将生产的数据放入队列,打印,解锁,一旦解锁之后,消费者 获得了执行机会。
消费者: 另一方面消费者就会通过unique_lock获得控制权,也就是获得锁,然后判断队列为空的话就一直盗用wait()函数阻塞在那里,等待其他线程来唤醒它。 而阻塞该线程时,该函数会自动解锁,允许其他线程执行。
生产者:再次回到生产者这里,生产者线程利用利用条件变量cond.notify_one()来通知阻塞的线程起来干活了。
消费者:阻塞在那里的消费者线程一旦得到notify唤醒,该函数取消阻塞并获取锁,然后取出队列中的数据,并打印,最后解锁。
生产者:再次回到生产者,然后生产者休眠1秒,这里休眠是为了模拟生产者生产慢的情况,实际开发的时候不要去休眠。最后减一,进入下一次生产。
以上就是利用条件变量来实现生产消费者模型,这个会大大降低CPU的占有率,当然代价就是编程稍微有点麻烦,但与这优化程序来比,这肯定是值的。
更多精彩内容,请关注同名公众:一点笔记alittle

以上是关于C++11多线程编程——生产消费者模型之条件变量的主要内容,如果未能解决你的问题,请参考以下文章

线程同步之经典模型 —— 生产者消费者模型

线程同步之经典模型 —— 生产者消费者模型

Go语言编程:使用条件变量Cond和channel通道实现多个生产者和消费者模型

[C++11 多线程同步] --- 条件变量的那些坑条件变量信号丢失和条件变量虚假唤醒(spurious wakeup)

[C++11 多线程同步] --- 条件变量的那些坑条件变量信号丢失和条件变量虚假唤醒(spurious wakeup)

[C++11 多线程同步] --- 条件变量的那些坑条件变量信号丢失和条件变量虚假唤醒(spurious wakeup)