C++11并发编程条件变量condition_variable

C++11 conditon、wait、notify_one、notify_all

一、条件变量std::conditon_variable、wait()、notify_one()

1.1、std::conditon_variable以及wait()和notify_one()

#include <iostream>
#include <thread>
#include <list>
#include <mutex>
#include <chrono>

class A
{
public:
	void inMsgRecvList()
	{
		for (int i = 0; i < 100000; ++i)
		{
				std::cout << "inMsgRecvList()执行插入一个元素" << i<<std::endl;
				std::unique_lock<std::mutex> myUniqueLock(myMutex1);
				msgRecvList.push_back(i);
				myCondition.notify_one();
				myUniqueLock.unlock();
		}
		return;
	}
	void outMsgRecvList()
	{
		int commond = 0;
		while (true)
		{
			{
				std::unique_lock<std::mutex> myUniqueLock(myMutex1);
				//wait()等待一个条件
				/*如果第二个参数(lambda表达式)的返回值是false,那么wait()将解锁互斥量,并阻塞到本行
				 阻塞到其他某个线程调用notify_one()成员函数为止
				 如果第二个参数的返回值是true,则wait立即返回
				如果wait()没有第二个参数,则会阻塞到本行解锁互斥量,直到某个线程调用notify_one();
				当其他线程调用notify_one,wait()被唤醒,wait()不断地尝试互斥锁,如果获取不到,就阻塞
				如果wait()有第二个参数,就判断返回值,如果是false(),解锁互斥量。再次等待被唤醒
				如果表达式为true这立即返回,程序继续执行
				如果没有第二个参数,被唤醒就向下执行
				*/
				myCondition.wait(myUniqueLock , [this] {
					if (!msgRecvList.empty())
					{
						return true;
					}
					return false;
					});
				commond = msgRecvList.front();
				msgRecvList.pop_front();
				myUniqueLock.unlock();
				std::cout << "取出一个元素" << commond<<std::endl;
				//std::this_thread::sleep_for(std::chrono::milliseconds(20));
			}
		}
	}
protected:
	std::list<int> msgRecvList;  //保存接收到的消息
	std::mutex myMutex1;
	std::condition_variable myCondition;
};

int main()
{
	A obja;
	std::thread myOutMsgObj(&A::outMsgRecvList, std::ref(obja));
	std::thread myInMsgObj(&A::inMsgRecvList, std::ref(obja));

	myOutMsgObj.join();
	myInMsgObj.join();
	return 0;
}

condition_variable条件变量是一个类
成员函数:
wait()第一个参数是unqinue_lock对象,第二个参数存在默认值
当wait()不存在第二个参数的时候,则会阻塞到本行并且对互斥量进行解锁,直到其他线程调用notify_one,当notify_one()被调用时,wait()函数尝试加锁,若加锁不成功,则会阻塞,加锁成功,就继续向下执行。
当wait()存在第二个参数的时候,如果第二个参数的值为false时,wait()函数会对互斥量进行解锁,并且阻塞到本行,直到其他线程调用notify_one(),如果第二个参数时true则wait()函数立即返回,程序继续向下执行
在这里插入图片描述
上述代码并非调用notify_one()函数的时候就立即进行操作,wait()函数需要先进行尝试加锁,如果加锁失败,并不会向下执行,直到加锁成功(需要于插入元素竞争互斥量),才会继续向下执行。(并非插入一个就取出一个)

	std::thread myOutMsgObj1(&A::outMsgRecvList, std::ref(obja));
	std::thread myOutMsgObj2(&A::outMsgRecvList, std::ref(obja));
	std::thread myInMsgObj(&A::inMsgRecvList, std::ref(obja));

当一个输入对应两个输入的时候,notify_one()只会唤醒一个wait()函数,具体唤哪一个函数不确定。
在这里插入图片描述

1.2、notify_all()

作用:可以同时唤醒多个线程wait()函数,notify_one()只能唤醒一个线程

#include <iostream>
#include <thread>
#include <list>
#include <mutex>
#include <chrono>

class A
{
public:
	void inMsgRecvList()
	{
		for (int i = 0; i < 100000; ++i)
		{
				std::cout << "inMsgRecvList()执行插入一个元素" << i<<std::endl;
				std::unique_lock<std::mutex> myUniqueLock(myMutex1);
				msgRecvList.push_back(i);
				myCondition.notify_all();
				myUniqueLock.unlock();
				std::this_thread::sleep_for(std::chrono::milliseconds(200));
		}
		return;
	}
	void test()
	{
		while (1)
		{
			std::unique_lock<std::mutex> myUniqueLock(myMutex1);
			myCondition.wait(myUniqueLock);
			std::cout << "其他的业务线程Id = " <<std::this_thread::get_id()<< std::endl;
			myUniqueLock.unlock();
		}
	}
	void outMsgRecvList()
	{
		int commond = 0;
		while (true)
		{
			{
				std::unique_lock<std::mutex> myUniqueLock(myMutex1);
				//wait()等待一个条件
				/*如果第二个参数(lambda表达式)的返回值是false,那么wait()将解锁互斥量,并阻塞到本行
				 阻塞到其他某个线程调用notify_one()成员函数为止
				 如果第二个参数的返回值是true,则wait立即返回
				如果wait()没有第二个参数,则会阻塞到本行解锁互斥量,直到某个线程调用notify_one();
				当其他线程调用notify_one,wait()被唤醒,wait()不断地尝试互斥锁,如果获取不到,就阻塞
				如果wait()有第二个参数,就判断返回值,如果是false(),解锁互斥量。再次等待被唤醒
				如果表达式为true这立即返回,程序继续执行
				如果没有第二个参数,被唤醒就向下执行
				*/
				myCondition.wait(myUniqueLock , [this] {
					if (!msgRecvList.empty())
					{
						return true;
					}
					return false;
					});
				commond = msgRecvList.front();
				msgRecvList.pop_front();
				std::cout << "取出一个元素" << commond <<"\t线程id =" << std::this_thread::get_id() << std::endl;
				myUniqueLock.unlock();
			}
		}
	}
protected:
	std::list<int> msgRecvList;  //保存接收到的消息
	std::mutex myMutex1;
	std::condition_variable myCondition;
};

int main()
{
	A obja;
	std::thread myOutMsgObj1(&A::outMsgRecvList, std::ref(obja));
	std::thread myOutMsgObj2(&A::test, std::ref(obja));
	std::thread myInMsgObj(&A::inMsgRecvList, std::ref(obja));

	myOutMsgObj1.join();
	myOutMsgObj2.join();
	myInMsgObj.join();
	return 0;
}

在这里插入图片描述
通过结果可以发现同时唤醒了两个线程进行操作。

  • 8
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值