C++新特性37_条件变量的C++封装(_Cnd_wait的使用;条件变量在C++中的封装类及使用;其代码使用与上篇基本一致;后期如果使用就采用此处封装的方法)

本文详细解析了C++中条件变量的_Cnd_wait用法,并展示了如何通过C++11的condition_variable和unique_lock进行封装,以实现线程间的高效协作。通过实例演示了如何避免死锁,确保信号通知后的锁获取。

接上篇:C++新特性36_条件变量的使用,前面介绍了条件变量的引入和使用,本篇介绍C++中是如何封装的及如何使用?

1. _Cnd_wait的使用

上篇的代码中主线程和子线程中均有_Mtx_lock(g_mtx);,在子线程中如果拿到锁,但是条件while (!g_isSet)成立,子线程陷入等待情况下,主线程是否可以拿到锁呢?

#include <iostream>
#include <string>
#include <mutex>
#include <thread>

//全局互斥体,用于同步
//用于发送消息
std::string g_str;

bool g_isSet = false;

//条件变量对象
_Cnd_t g_cnd;
//互斥体
_Mtx_t g_mtx;

//B 子线程
// 利用条件变量,可以控制线程执行的逻辑顺序,也可以用来传递消息
void worker_thread() {

	//睡眠一段时间,使得可以转到主线程
	//std::this_thread::sleep_for(std::chrono::seconds(1));
	_Mtx_lock(g_mtx);
	//子线程接收通知
	while (!g_isSet) {
	    //都是原子性:不可以被打断
	    //1. 等待g_cnd被通知
		//2. g_mtx 会被释放
		//3. 当等到了g_cnd被触发时,g_mtx会被重新获取
		_Cnd_wait(g_cnd, g_mtx); //陷入等待的过程,等到信号
	}

	printf("%s\r\n", g_str.c_str());

	_Mtx_unlock(g_mtx);
}


//A 主线程
int main() {

	//初始化 对应了构造函数,需要使用的是一个指针 _Cnd_init(_Cnd_t *)
	_Cnd_init(&g_cnd);
	//选择普通互斥体类型
	_Mtx_init(&g_mtx, _Mtx_plain);

	//起一条子线程
	std::thread thd(worker_thread);
	//std::this_thread::sleep_for(std::chrono::seconds(1)); //主线程休眠就可以保证子线程先执行等待主线程的信号

	//主线程发送信号(通知)
	_Cnd_signal(g_cnd);

	_Mtx_lock(g_mtx);
	g_isSet = true;
	g_str = "Hello World!";
	_Mtx_unlock(g_mtx);

	//表示主线程已经准备完毕,通知子线程开始处理
	//主线程发送信号(通知)
	_Cnd_signal(g_cnd);//给条件变量发信号

	thd.join();

	//析构条件变量
	_Cnd_destroy(g_cnd);
	_Mtx_destroy(g_mtx);
	return 0;
}

设置断点,运行结果如下:执行完子线程之后,主线程也是可以拿到锁的,如果拿不到,程序就会处于死锁的状态
在这里插入图片描述
因此条件变量的_Cnd_wait(g_cnd, g_mtx);等待语句隐藏了一层含义:等待条件变量对象g_cnd被通知;g_mtx 会被释放;当等到了g_cnd被触发时(发送信号),g_mtx会被重新获取。内部都是原子性操作

2.条件变量在C++中的封装类及使用

  • condition_variable 是c++11对条件变量的封装,配合std::unique_lockstd::mutex进行wait操作。
  • condition_variable_any,搭配任意带有lock、unlock语义的mutex使用,效率 condition_variable 低。

使用封装的代码如下,基本与上面的代码是一致的:

#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>

std::string str;
bool g_isSet = false;
std::mutex m;
std::condition_variable cv;


void worker_thread() {

	std::cout << "Worker thread start\n";

	{
		std::unique_lock<std::mutex> lk(m);
		//利用匿名函数对上面while()的写法进行替换
		cv.wait(lk, [&] {return g_isSet; });
		std::cout << str.c_str() << std::endl;
	}

	std::cout << "Worker thread end\n";
}


int main() {

	std::thread thd(worker_thread);

	std::this_thread::sleep_for(std::chrono::seconds(1));

	{
		std::lock_guard<std::mutex> lk(m);
		g_isSet = true;
		str = "hello";
	}

	cv.notify_one();

	thd.join();


	std::cout << "Main thread signals end\n";
}

运行结果:
在这里插入图片描述

3. 学习视频地址:条件变量的C++封装

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十月旧城

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值