前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++ 条件变量(condition_variable)

C++ 条件变量(condition_variable)

作者头像
Ch_Zaqdt
发布2020-02-15 17:27:53
13.7K1
发布2020-02-15 17:27:53
举报
文章被收录于专栏:Zaqdt_ACMZaqdt_ACM

       先贴一个condition_variable的讲解:https://en.cppreference.com/w/cpp/thread/condition_variable,很详细也很全面,但是是英文的,劝退了一部分英语不好的人(也包括我),但是借助翻译还是大概可以看下来的,而且里面的两个代码也很有代表性,使用的生产者消费者模式,推给大家。

       condition_variable是一个类,搭配互斥量mutex来用,这个类有它自己的一些函数,这里就主要讲wait函数和notify_*函数,故名思意,wait就是有一个等待的作用,notify就是有一个通知的作用。主要用法这里就不再赘述了,简而言之就是程序运行到wait函数的时候会先在此阻塞,然后自动unlock,那么其他线程在拿到锁以后就会往下运行,当运行到notify_one()函数的时候,就会唤醒wait函数,然后自动lock并继续下运行。

       当然wait还有第二个参数,这个参数接收一个布尔类型的值,当这个布尔类型的值为false的时候线程就会被阻塞在这里,只有当该线程被唤醒之后,且第二参数为true才会往下运行。

       notify_one()每次只能唤醒一个线程,那么notify_all()函数的作用就是可以唤醒所有的线程,但是最终能抢夺锁的只有一个线程,或者说有多个线程在wait,但是用notify_one()去唤醒其中一个线程,那么这些线程就出现了去争夺互斥量的一个情况,那么最终没有获得锁的控制权的线程就会再次回到阻塞的状态,那么对于这些没有抢到控制权的这个过程就叫做虚假唤醒。那么对于虚假唤醒的解决方法就是加一个while循环,比如下面这样:

代码语言:javascript
复制
while (que.size() == 0) {
	cr.wait(lck);
}

       这个就是当线程被唤醒以后,先进行判断,是否可以去操作,如果可以再去运行下面的代码,否则继续在循环内执行wait函数。

       补充一个小的知识点,上面所说的多个线程等待一个唤醒的情况叫做惊群效应(了解的不多,大家可以自己查一下)。

       下面就贴一个生产者消费者模式的代码:

代码语言:javascript
复制
#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;
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-02-07 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档