《c++新经典》C++11并发与多线程笔记(8)

八、 condition_variable、wait、notify_one、notify_all

在这里插入图片描述

1.条件变量condition_variable、wait、notify_one、notify_all

std::condition_variable实际上是一个类,是一个和条件相关的类,等待条件达成
这个类需要和互斥量配合来工作,用的时候我们要生成这个类的对象
线程A:等待一个条件满足
线程B:专门往消息队列中扔消息(数据)

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <list>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;


class A
{
public:
	//把收到的消息(玩家命令)插入到一个队列的线程
	void inMesgRecvQueue()
	{
		for (int i = 0; i < 100000; ++i)
		{
			cout << "inMesgRecvQueue执行,插入一个元素" << i << endl;
			//其他处理...
			std::unique_lock<std::mutex> my_unique_lock(my_mutex1);
			list_msg.push_back(i);
			//尝试把wait()的线程唤醒,执行完这行,那么outMesgRecvQueue里面的wait()就会被唤醒
			//加入outMesgRecvQueue()正在处理一个事务,需要一段时间,而不是卡在wait()那里等待你唤醒,
			//那么此时这个notify_one()调用就无效
			my_cond.notify_one();
			//其他处理。。。。
		}
		return;
	}

	//把消息队列从容器中取出来的线程
	void outMesgRecvQueue()
	{
		int command = 0;
		while (true)
		{
			std::unique_lock<std::mutex> my_unique_lock(my_mutex1);
			//wait()用来等一个东西
			//如果第二个参数lambda表达式返回值是false, 那么wait()将直接返回

			//如果第二个参数lambda表达式返回值是false,那么wait()将会解锁,并堵塞到本行
			//堵塞到其他某个线程调用modify_one()为止

			//如果wait()没有第二个参数:my_cond.wait(my_unique_lock),那么就跟lambda表达式返回值是false一样
			//wait()将会解锁互斥量,并堵塞到本行,堵塞到其他某个线程调用modify_one()为止

			//当其他线程调用modify_one() 将本wait()(原来是睡着/堵塞的状态)的状态唤醒后,wait()就又开始干活了,
			//恢复wait()后干什么活?
			//(a)wait()不断尝试重新获取互斥量锁,如果获取不到,那么流程就卡在wait这里等着获取;
					//如果获取到了(等于加了锁),那么wait就继续执行(b)
			//(b)
			// (b.1)如果wait有第二个参数(lambda表达式),就判断这个lambda表达式,
					//如果lambda表达式为false,那wait又对互斥量解锁,然后又休眠等待再次被唤醒
			// (b.2)如果lambda表达式为true,则wait返回,流程走下来(此时,互斥锁被锁着)
			// (b.3)如果wait没有第2个参数,则wait返回,流程走下来。
			my_cond.wait(my_unique_lock, [this]//一个lambda表达式就是一个可调用对象(相当于一个函数)
			{
				if (!list_msg.empty())
				{
					return true;
				}
				return false;
			});

			//流程只要能走到这里来,这个互斥锁一定是锁着的,同事outMesgRecvQueue至少是有一条数据的。
			//一会再写其他的
			command = list_msg.front();//返回第一个元素,但不返回元素是否存在
			list_msg.pop_front();//移除第一个元素,但不返回
			my_unique_lock.unlock();//因为unique_lock()的灵活性,我们可以随时unlock,以免锁住太长时间。
			std::cout << "outMesgRecvQueue执行取出一个元素:" << command <<
				" this_thread = " << std::this_thread::get_id() << std::endl;

			//执行一些具体动作,比如帮助玩家抽卡,抽卡需要100毫秒的处理时间
			//。。。
			//执行100毫秒
			//
			//
		}
	}
protected:
private:
	std::list<int> list_msg;//专门用于代表玩家给咱们发送过来的命令
	std::mutex my_mutex1;//创建了一个互斥量

	//std::condition_variable实际上是一个类,是一个和条件相关的类,等待条件达成
	//这个类需要和互斥量配合来工作,用的时候我们要生成这个类的对象
	std::condition_variable my_cond;//生成一个条件变量对象
};


int main(int argc, char* argv[])
{
	A myobja;
	//第2个参数是引用,才能保证线程里面用的是同一个对象
	std::thread myOutMsgobj(&A::outMesgRecvQueue, &myobja);
	std::thread myInMsgobj(&A::inMesgRecvQueue, &myobja);
	myOutMsgobj.join();
	myInMsgobj.join();
	system("pause");
	return 0;
}

三、notify_all()

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <list>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;


class A
{
public:
	//把收到的消息(玩家命令)插入到一个队列的线程
	void inMesgRecvQueue()
	{
		for (int i = 0; i < 100000; ++i)
		{
			cout << "inMesgRecvQueue执行,插入一个元素" << i << endl;
			//其他处理...
			std::unique_lock<std::mutex> my_unique_lock(my_mutex1);
			list_msg.push_back(i);
			//尝试把wait()的线程唤醒,执行完这行,那么outMesgRecvQueue里面的wait()就会被唤醒
			//加入outMesgRecvQueue()正在处理一个事务,需要一段时间,而不是卡在wait()那里等待你唤醒,
			//那么此时这个notify_one()调用就无效
			my_cond.notify_all();
			//其他处理。。。。
		}
		return;
	}

	//把消息队列从容器中取出来的线程
	void outMesgRecvQueue()
	{
		int command = 0;
		while (true)
		{
			std::unique_lock<std::mutex> my_unique_lock(my_mutex1);
			//wait()用来等一个东西
			//如果第二个参数lambda表达式返回值是false, 那么wait()将直接返回

			//如果第二个参数lambda表达式返回值是false,那么wait()将会解锁,并堵塞到本行
			//堵塞到其他某个线程调用modify_one()为止

			//如果wait()没有第二个参数:my_cond.wait(my_unique_lock),那么就跟lambda表达式返回值是false一样
			//wait()将会解锁互斥量,并堵塞到本行,堵塞到其他某个线程调用modify_one()为止

			//当其他线程调用modify_one() 将本wait()(原来是睡着/堵塞的状态)的状态唤醒后,wait()就又开始干活了,
			//恢复wait()后干什么活?
			//(a)wait()不断尝试重新获取互斥量锁,如果获取不到,那么流程就卡在wait这里等着获取;
					//如果获取到了(等于加了锁),那么wait就继续执行(b)
			//(b)
			// (b.1)如果wait有第二个参数(lambda表达式),就判断这个lambda表达式,
					//如果lambda表达式为false,那wait又对互斥量解锁,然后又休眠等待再次被唤醒
			// (b.2)如果lambda表达式为true,则wait返回,流程走下来(此时,互斥锁被锁着)
			// (b.3)如果wait没有第2个参数,则wait返回,流程走下来。
			my_cond.wait(my_unique_lock, [this]//一个lambda表达式就是一个可调用对象(相当于一个函数)
			{
				if (!list_msg.empty())
				{
					return true;
				}
				return false;
			});

			//流程只要能走到这里来,这个互斥锁一定是锁着的,同事outMesgRecvQueue至少是有一条数据的。
			//一会再写其他的
			command = list_msg.front();//返回第一个元素,但不返回元素是否存在
			list_msg.pop_front();//移除第一个元素,但不返回
			my_unique_lock.unlock();//因为unique_lock()的灵活性,我们可以随时unlock,以免锁住太长时间。
			std::cout << "outMesgRecvQueue执行取出一个元素:" << command <<
				" this_thread = " << std::this_thread::get_id() << std::endl;

			//执行一些具体动作,比如帮助玩家抽卡,抽卡需要100毫秒的处理时间
			//。。。
			//执行100毫秒
			//
			//
		}
	}
protected:
private:
	std::list<int> list_msg;//专门用于代表玩家给咱们发送过来的命令
	std::mutex my_mutex1;//创建了一个互斥量

	//std::condition_variable实际上是一个类,是一个和条件相关的类,等待条件达成
	//这个类需要和互斥量配合来工作,用的时候我们要生成这个类的对象
	std::condition_variable my_cond;//生成一个条件变量对象
};


int main(int argc, char* argv[])
{
	A myobja;
	//第2个参数是引用,才能保证线程里面用的是同一个对象
	std::thread myOutMsgobj(&A::outMesgRecvQueue, &myobja);
	std::thread myInMsgobj(&A::inMesgRecvQueue, &myobja);
	myOutMsgobj.join();
	myInMsgobj.join();
	system("pause");
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值