开发者社区> Oracle中文开发者社区> 正文

c++线程同步——条件变量(condition_variable)

简介: c++线程同步——条件变量(condition_variable)
+关注继续查看

@[TOC]

1、为何要引入条件变量?

例子

在一条生产线上有一个仓库,当生产者生产时需要锁住仓库独占,而消费者去产品时也需要锁住仓库独占。
如果,生产者发现仓库满了,那么他就不能生产了,编程了阻塞状态。但是此时生产者独占仓库,消费者又无法进入仓库消耗产品,这样就造成了一个僵死的状态。
我们需要一种机制,当互斥量被锁住以后发现当前线程还是无法完成自己的操作,那么它应该释放互斥量,让其他线程哦工作。

  1. 可以采用轮询的方式,不停的查询你需要的条件。
  2. 让系统来帮你查询条件,使用条件变量。

2、不使用条件变量

demo

#include<iostream>
#include <thread>
#include<mutex>
#include<deque>
#include<chrono>

using namespace std;

mutex mtx;
deque<int> q;

//线程A,producer
void task1()
{
    int i = 0;
    while(true)
    {
        unique_lock<mutex> lock(mtx);
        if (q.size() < 1000)
        {
            if (i < 999)
            {
                q.push_back(i);
                i++;
            }
            else
            {
                i = 0;
            }
        }
        else
        {
            // std::this_thread::sleep_for(std::chrono::seconds(1));;
        }
    }
}

//线程B,consumer
void task2()
{
    int da = 0;
    while (true)
    {
        unique_lock<mutex> lock(mtx);
        if (!q.empty())
        {
            da = q.front();
            q.pop_front();
            cout << "get value from que:" << da << endl;
            cout << "que.size:" << q.size()<<endl;
        }
    }
}

int main()
{
    cout << "que.size:" << q.size() << endl;
    thread t2(task2);
    thread t1(task1);
 
    t1.join();
    t2.join();
}

3、使用条件变量

3.1、互斥锁有什么问题?

尝试获取锁的人会一直等待,浪费cpu资源。(功耗和性能浪费)

3.2、条件变量

提供睡眠/唤醒机制,避免无意义的等待。
条件变量是允许多个线程相互交流的同步原语。它允许一定量的线程等待(可以定时)另一线程的提醒,然后再继续。条件变量始终关联到一个互斥。
定义于头文件 <condition_variable>

3.3、条件变量成员函数

通知

通知成员函数解释
notify_one通知一个等待的线程(公开成员函数)
notify_all通知所有等待的线程(公开成员函数)

等待

等待成员函数解释
wait阻塞当前线程,直到条件变量被唤醒(公开成员函数)
wait_for阻塞当前线程,直到条件变量被唤醒,或到指定时限时长后(公开成员函数)
wait_until阻塞当前线程,直到条件变量被唤醒,或直到抵达指定时间点(公开成员函数)

简单说下,如果是新人,简单理解wait和notify_one两个函数就行了,基本就明白了条件变量的原理,如下面的demo,wait就是等待notify的通知后再执行

3.4、demo

#include<iostream>
#include <thread>
#include<mutex>
#include<deque>
#include<chrono>
#include<condition_variable>

using namespace std;

mutex mtx;
deque<int> q;
condition_variable cv;

//线程A,producer
void task1()
{
    int i = 0;
    while(true)
    {
        unique_lock<mutex> lock(mtx);
        if (q.size() < 1000)
        {
            if (i < 99)
            {
                q.push_back(i);
                cv.notify_one();//cv.notify_all();
                i++;
            }
            else
            {
                i = 0;
            }
        }
        else
        {
            cv.notify_one();
            //std::this_thread::sleep_for(std::chrono::seconds(1));;
        }
    }
}

//线程B,consumer
void task2()
{
    int da = 0;
    while (true)
    {
        unique_lock<mutex> lock(mtx);
        if (q.empty())//如果有多个消费者,此处应该为while(q.empty())
        {
            cv.wait(lock);
        }
        da = q.front();
        q.pop_front();
        cout << "get value from que:" << da << endl;
        cout << "que.size:" << q.size() << endl;
    }
}

int main()
{
    cout << "que.size:" << q.size() << endl;
    thread t2(task2);
    thread t1(task1);
 
    t1.join();
    t2.join();
}

3.4、总结

  • 使用条件变量的意义在于,消费者在没有可消费的产品时,采用休眠,而非无意义的空转,浪费cpu的计算资源。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
【C++ 语言】线程安全队列 ( 条件变量 | 线程调度 )(二)
【C++ 语言】线程安全队列 ( 条件变量 | 线程调度 )(二)
137 0
【C++ 语言】线程安全队列 ( 条件变量 | 线程调度 )(一)
【C++ 语言】线程安全队列 ( 条件变量 | 线程调度 )(一)
90 0
C++ 并发编程之互斥锁和条件变量的性能比较
C++ 并发编程之互斥锁和条件变量的性能比较介绍本文以最简单生产者消费者模型,通过运行程序,观察该进程的cpu使用率,来对比使用互斥锁 和 互斥锁+条件变量的性能比较。 本例子的生产者消费者模型,1个生产者,5个消费者。
1194 0
linux C++ 多线程使用pthread_cond 条件变量
1. 背景 多线程中经常需要使用到锁(pthread_mutex_t)来完成多个线程之间的互斥操作。 但是互斥锁有一个明显到缺点: 只有两种状态,锁定和非锁定。 而条件变量则通过允许线程阻塞并等待另一个线程发送唤醒信号的方法弥补了互斥锁的不足,它常和互斥锁一起使用。
1809 0
C++ STL学习之【vector的使用】
vector 是表示可变大小数组的序列 容器,其使用的是一块 连续 的空间,因为是动态增长的数组,所以 vector 在空间不够时会扩容;vector 优点之一是支持 下标的随机访问,缺点也很明显,头插或中部插入效率很低,这和我们之前学过的 顺序表 性质很像,不过在结构设计上,两者是截然不同的
38 0
C++ STL学习之【string类的模拟实现】
string 本质上就是一个专注于存储字符的顺序表,使用起来很方便;但在模拟实现 string 时,有许多值得注意的点,下面就来看看 string 类是如何诞生的吧
52 0
C++ STL 学习之【string】
STL 是 C++ 的重要组成部分,由六大部分构成:伪函数、空间配置器、算法、容器、迭代器 和 配接器,其中各种各样的 容器 可以很好的辅助我们写程序,比如今天要介绍的 string,有了它之后,我们对字符串的操作就能变得行云流水
47 0
【查找算法】解析学习四大常用的计算机查找算法 | C++
在数据处理的过程中,能否在最短时间内去找到目的数据,是编程开发人员非常值得关心的一个问题。所谓查找,也被称为搜索,它是指从数据文件中找出满足某些条件的记录。在数据结构中描述算法时习惯用“查找”,而在搜索引擎中找信息或资料时习惯用“搜索”。我们在电话簿中查找某人的电话号码,电话簿就像是数据文件库,而姓名就是去查找电话号码的键值。我们经常使用的搜索引擎所设计的Spider程序(网页抓取程序爬虫)会主动经由网站上的超链接“爬行”到另一个网站,搜集每个网站上的信息并且收录到数据库中,这其中就涉及到了今天要讲的查找算法。
23 0
【奇妙的数据结构世界】用图像和代码对堆栈的使用进行透彻学习 | C++
简单来说,数据结构是一种辅助程序设计并且进行优化的方法论,它不仅讨论数据的存储与处理的方法,同时也考虑到了数据彼此之间的关系与运算,从而极大程度的提高程序执行的效率,减少对内存空间的占用等。不同种类的数据结构适用于不同的程序应用,选择合适正确的数据结构,可以让算法发挥出更大的性能,给设计的程序带来更高效率的算法。
21 0
文章
问答
文章排行榜
最热
最新
相关电子书
更多
继承与功能组合
立即下载
对象的生命期管理
立即下载
移动与复制
立即下载