首页 > 编程语言 >C++ 条件变量(condition_variable)

C++ 条件变量(condition_variable)

时间:2022-10-06 20:56:33浏览次数:81  
标签:size std mtx C++ que variable include condition wait

生产者消费者模式的代码(以下代码参考链接):

#include <iostream>
#include <thread>
#include <mutex>
#include <queue>
#include <windows.h>
#include <condition_variable>

std::mutex mtx;        // 全局互斥锁
std::queue<int> que;   // 全局消息队列
std::condition_variable cr;   // 全局条件变量
int cnt = 1;           // 数据

void producer() {
	while(true) {
		{
			std::unique_lock<std::mutex> lck(mtx);
			// 在这里也可以加上wait 防止队列堆积  while(que.size() >= MaxSize) que.wait();
			que.push(cnt);
			std::cout << "向队列中添加数据:" << cnt ++ << std::endl;
			// 这里用大括号括起来了 为了避免出现虚假唤醒的情况 所以先unlock 再去唤醒
		}
		cr.notify_all();       // 唤醒所有wait
	}
}

void consumer() {
	while (true) {
		std::unique_lock<std::mutex> lck(mtx);
		while (que.size() == 0) {           // 这里防止出现虚假唤醒  所以在唤醒后再判断一次
			cr.wait(lck);
		}
		int tmp = que.front();
		std::cout << "从队列中取出数据:" << tmp << std::endl;
		que.pop();
	}
}

int main()
{
	std::thread thd1[2], thd2[2];
	for (int i = 0; i < 2; i++) {
		thd1[i] = std::thread(producer);
		thd2[i] = std::thread(consumer);
		thd1[i].join();
		thd2[i].join();
	}
	return 0;
}

while (que.size() == 0)的作用:while (que.size() == 0)不能替换为if(que.size() == 0) ,这是为了防止虚假唤醒。如果while (que.size() == 0)替换为if(que.size() == 0) 可能会出现如下结果:

  • th2[0]拿完了队列里最后一个产品正在处理,此时队列为空。
  • th2[1]想去队列里拿发现已经空了,所以停在了wait上。
  • th1[0]拿到mtx后,往队列添加了一个产品,并执行了notify_one通知处于等待状态的消费者。
  • 由于收到了notify,th2[1]准备要被调度,但是th2[0]此时恰好处理完了手头的任务,并进行了下一轮循环,抢在th2[1]之前拿到了mtx并取走了th1[0]刚放进去的产品,此时th2[1]被阻塞,随后th2[0]释放了mtx。
  • th2[0]释放了mtx后,th2[1]终于拿到了mtx却发现队列又是空的,这就是一次虚假唤醒,对于这种情况th2[1]需要继续wait。要想实现“继续wait”,就需要使用while (que.size() == 0),而不是if(que.size() == 0)

wait()有的第二个形参可用于代替while (que.size() == 0)

#include <iostream>
#include <thread>
#include <mutex>
#include <queue>
#include <windows.h>
#include <condition_variable>

std::mutex mtx;        // 全局互斥锁
std::queue<int> que;   // 全局消息队列
std::condition_variable cr;   // 全局条件变量
int cnt = 1;           // 数据

void producer() {
	while(true) {
		{
			std::unique_lock<std::mutex> lck(mtx);
			// 在这里也可以加上wait 防止队列堆积  while(que.size() >= MaxSize) que.wait();
			que.push(cnt);
			std::cout << "向队列中添加数据:" << cnt ++ << std::endl;
			// 这里用大括号括起来了 为了避免出现虚假唤醒的情况 所以先unlock 再去唤醒
		}
		cr.notify_all();       // 唤醒所有wait
	}
}

void consumer() {
	while (true) {
		std::unique_lock<std::mutex> lck(mtx);
		
                cr.wait(lck,[]{return que.size() > 0;}); // wait被唤醒以后,如果判断return为假时,继续调用wait
		
                int tmp = que.front();
		std::cout << "从队列中取出数据:" << tmp << std::endl;
		que.pop();
	}
}

int main()
{
	std::thread thd1[2], thd2[2];
	for (int i = 0; i < 2; i++) {
		thd1[i] = std::thread(producer);
		thd2[i] = std::thread(consumer);
		thd1[i].join();
		thd2[i].join();
	}
	return 0;
}

标签:size,std,mtx,C++,que,variable,include,condition,wait
From: https://www.cnblogs.com/codingbigdog/p/16758459.html

相关文章

  • C++里的花括号{},块,作用域
    在C/C++中大括号指明了变量的作用域,在大括号内声明的局部变量其作用域自变量声明开始,到大括号之后终结,举例如下:intmain(){inta=0;{intb=0;......
  • c++小游戏
    #include<bits/stdc++.h>#include<windows.h>#include<stdio.h>#include<conio.h>#include<time.h>usingnamespacestd;intmain(){MessageBox(NULL,TEXT("......
  • 条件期望:Conditional Expectation 举例详解之入门之入门之草履虫都说听懂了
    我知道有很多人理解不了“条件期望”(ConditionalExpectation)这个东西,有的时候没看清把随机变量看成事件,把\(\sigma\)-algebra看成随机变量从而思路全错的时候,我也......
  • c++快读快写
    快读快写是利用\(getchar()\)和\(putchar()\)比\(cin\)和\(cout\)速度快的特点来对输入和输出进行优化快读intread(){intx=0,f=1;charch=getchar();......
  • C++ 关键字四种cast类型转换
    1.23四种cast类型转换​作用:克服c中强制类型转化带来的风险,C++引入四种更加安全的强制类型转换运算符(明确转换的目的,偏于程序的维护和分析)const_cast://1.去除const属......
  • C++ 和 Python 的赋值操作 (等号“=“) 的区别
    C++和Python的赋值操作("=")的区别C++的赋值操作总是默认执行拷贝拷贝出来的副本与原来变量的地址不同除非是指针拷贝给指针的浅拷贝才会指向相同地址autoa=b;改变......
  • leetcode 6 Z字形变化 C/C++ 找规律解法 / 用容器的解法
    找规律,除了一行和两行需要特殊处理之外,其他的规律是一样的。/*class Solution {public:    string convert(string s, int numRows) {       ......
  • C++ 泛型(模板与容器)
    文章目录​​一、泛型的基本思想:​​​​函数模板的性质​​​​C++模版函数/类的语法​​​​类模板的性质​​​​二、C++STL简介​​​​2.1算法(algorithm)​​​​2.......
  • C++虚函数
    C++三大特性:封装、继承、多态在这里谈下多态,多态指的是在类之间存在继承关系时,有的函数声明为virtual函数,当我们将子类指针或引用转化为父类指针或引用时,调用某个虚函数时......
  • OpenCV-Python-C++ 全套视频详讲
    更多资料请关注公众号:计算机视觉与图形学实战​​2021OpenCV-C++课程实践(理论与实践)​​​​2021年OpenCV-Python从入门到实战全套课程(附带课程课件资料+课件笔记)​​​​......