一、条件变量std::condition_variable、wait()、notify_one()
wait():用来等待一个东西
如果第二个参数lambda表达式返回 true ,直接返回,互斥量锁住;
如果第二个参数lambda表达式返回false ,wait() 将互斥量解锁,并堵塞到本行;直到某个线程调用notify_one()成员函数为止 将wait()堵塞状态唤醒 wait开始干活。
1.wait()不断尝试重新获取互斥量锁,如果获取不到,流程卡到此处,如果获取到,走下
2.上锁(获取到锁等于上锁)
2.1 如果wait有第二个参数lambda表达式,就判断参数表达式。如果返回false,wait() 将解锁互斥量,并堵塞到本行,等待notify_one()唤醒。如果返回为true,wait返回,流程往下走,此时互斥锁是锁着的。
2.3如果没有第二个参数,wait返回,流程往下走。my_cond.wait(sbguard1)直接为false堵塞。
二、notify_all() 唤醒所有线程的wait()
// 线程6.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<thread>
#include<iostream>
using namespace std;
#include<vector>
#include<list>
#include<mutex>
class A {
public:
//把收到的消息(玩家命令)写入到一个队列线程
void inMsgRecvQueue()
{
for (int i = 0; i<10000; i++)
{
cout << "inMesRecvQueue()执行,插入元素" << i << endl;
std::unique_lock<std::mutex> sbguard1(my_mutex1);
msgRecvQueue.push_back(i); //假设数字为接受的命令,直接进入消息队
//假如outMsgRecvQueue()正在处理一个事务,需要一段时间,而不是卡在wait()那里等待,此时notify_one调用无效果
my_cond.notify_one(); //尝试吧wait()唤醒 只能唤醒一个
//my_cond.notify_all();
}
}
//把数据从消息队列中取出的线程
void outMsgRecvQueue()
{
int command = 0;
while (true)
{
std::unique_lock<std::mutex> sbguard1(my_mutex1);
my_cond.wait(sbguard1, [this] { //一个lambda 可调用对象
if (!msgRecvQueue.empty())
return true;
return false;
});
//流程走到这,这个互斥锁一定是锁着的 同时msgRecvQueue至少有一条数据
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
cout << "************outMsgRecvQueue()执行,取出一个元素=" << command << "thread ID = " << std::this_thread::get_id() << endl;
sbguard1.unlock();//因为unique_lock的灵活性,unlock随时解锁
/*
处理其他程序需要100ms
*/
}
}
private:
list<int> msgRecvQueue;//容器,专门用于代表玩家发送过来的消息
mutex my_mutex1;//创建互斥量
std::condition_variable my_cond;//生成一个条件变量对象
};
int main()
{
A myobj;
thread myOutMsgObj(&A::outMsgRecvQueue, &myobj);//第二个参数是引用 避免复制
thread myOutMsgObj1(&A::outMsgRecvQueue, &myobj);
thread myInMsgObj(&A::inMsgRecvQueue, &myobj);
myOutMsgObj.join();
myOutMsgObj1.join();
myInMsgObj.join();
cout << "主线程结束" << endl;
return 0;
}