菜鸟笔记
提升您的技术认知

多线程 condition_variable、wait、notify_one、notify_all使用方法

条件变量condition_variable

假设有两个线程,一个线程A一个线程B。
线程A:等待一个条件满足.
线程B:专门往消息队列中扔消息(数据)
condition_variable是一个类,和条件相关的类,等待一个条件完成,需要和互斥量配合工作,用的时候需要生成这个类的对象。

condition_variable成员函数wait


第一个参数是一个锁,第二个参数是一个可调用对象。
如果第二个参数返回true,wait()直接返回。
如果第二个参数返回false,那么wati()将解锁互斥量,并堵塞直到其他某个线程调用notify_one()成员函数为止。
如果wait()没有第二个参数,那么就和第二个参数返回false的效果一样。

wait唤醒后,wait将干以下工作:
1.不断尝试重新获取互斥量锁,如果获取不到,流程就卡在wait这里等着获取,如果获取获取到了就继续执行2
2.获取到了锁然后上锁,如果wait有第二个参数,就判断第二个参数,如果第二个参数返回false,那wait又解锁互斥量,并堵塞直到其他某个线程调用notify_one()成员函数为止。
3.如果第二个参数返回true,则wait返回,流程走下去。
4.如果没有第二个参数,wait返回,流程走下去。

condition_variable成员函数notify_one

其他线程调用notify_one()将wait的状态唤醒后,wait恢复工作。
如果wait并没有堵塞,那么此时notify_one调用可能就没有效果.

使用例子

class A
{
  
private:
	list<int>msgqueue;
	mutex mymutex1;
	condition_variable mycon;//生成一个条件变量对象
public:
	void MsgEnqueue()
	{
  
		int commmand = 0;
		while (true)
		{
  
			unique_lock<mutex>l(mymutex1);
			mycon.wait(l, [this] 
			{
  
				if (!msgqueue.empty())
					return true;
				return false;
			});
			commmand = msgqueue.front();
			msgqueue.pop_front();
			l.unlock();//随时unlock()
			cout << "MsgEnqueue执行,取出一个元素 " << commmand << endl;

		}

		return;
	}
	void MsgDequeue()
	{
  

		for (int i = 0; i < 10000; ++i)
		{
  
			cout << "MsgDequeue执行,插入一个元素" << i << endl;
			unique_lock<mutex>l(mymutex1);
			msgqueue.push_back(i);
			mycon.notify_one();//尝试把wait()线程唤醒
		}

	}
};
int main()
{
  
	A a;
	thread t1(&A::MsgEnqueue, &a);
	thread t2(&A::MsgDequeue, &a);
	t1.join();
	t2.join();
	cout << endl;
}

condition_variable成员函数notify_all

唤醒所有wait()