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的计算资源。
相关文章
|
3天前
|
Java 程序员 调度
【JavaEE】线程创建和终止,Thread类方法,变量捕获(7000字长文)
创建线程的五种方式,Thread常见方法(守护进程.setDaemon() ,isAlive),start和run方法的区别,如何提前终止一个线程,标志位,isinterrupted,变量捕获
|
1月前
|
缓存 安全 C++
C++无锁队列:解锁多线程编程新境界
【10月更文挑战第27天】
69 7
|
1月前
|
消息中间件 存储 安全
|
2月前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
60 1
|
2月前
|
存储 并行计算 安全
C++多线程应用
【10月更文挑战第29天】C++ 中的多线程应用广泛,常见场景包括并行计算、网络编程中的并发服务器和图形用户界面(GUI)应用。通过多线程可以显著提升计算速度和响应能力。示例代码展示了如何使用 `pthread` 库创建和管理线程。注意事项包括数据同步与互斥、线程间通信和线程安全的类设计,以确保程序的正确性和稳定性。
|
2月前
|
存储 前端开发 C++
C++ 多线程之带返回值的线程处理函数
这篇文章介绍了在C++中使用`async`函数、`packaged_task`和`promise`三种方法来创建带返回值的线程处理函数。
88 6
|
2月前
|
缓存 负载均衡 Java
c++写高性能的任务流线程池(万字详解!)
本文介绍了一种高性能的任务流线程池设计,涵盖多种优化机制。首先介绍了Work Steal机制,通过任务偷窃提高资源利用率。接着讨论了优先级任务,使不同优先级的任务得到合理调度。然后提出了缓存机制,通过环形缓存队列提升程序负载能力。Local Thread机制则通过预先创建线程减少创建和销毁线程的开销。Lock Free机制进一步减少了锁的竞争。容量动态调整机制根据任务负载动态调整线程数量。批量处理机制提高了任务处理效率。此外,还介绍了负载均衡、避免等待、预测优化、减少复制等策略。最后,任务组的设计便于管理和复用多任务。整体设计旨在提升线程池的性能和稳定性。
87 5
|
2月前
|
C++
C++ 多线程之线程管理函数
这篇文章介绍了C++中多线程编程的几个关键函数,包括获取线程ID的`get_id()`,延时函数`sleep_for()`,线程让步函数`yield()`,以及阻塞线程直到指定时间的`sleep_until()`。
46 0
|
2月前
|
资源调度 Linux 调度
Linux C/C++之线程基础
这篇文章详细介绍了Linux下C/C++线程的基本概念、创建和管理线程的方法,以及线程同步的各种机制,并通过实例代码展示了线程同步技术的应用。
36 0
Linux C/C++之线程基础
|
2月前
|
C语言 C++
实现两个变量值的互换[C语言和C++的区别]
实现两个变量值的互换[C语言和C++的区别]
29 0