unique_lock可以取代lock_guard。
#include<thread>
#include<iostream>
#include<list>
#include<mutex>
using namespace std;
class A
{
public:
//把收到的消息(玩家命令)入到一个队列的线程
void inMsgRecvQueue()
{
for (int i = 0; i < 100; ++i)
{
cout << "inMsgRecvQueue()执行,插入一个元素" << i << endl;
std::unique_lock<std::mutex> sbguard1(my_mutex);
msgRecvQueue.push_back(i); //假设这个数字就是收到的命令,直接放到消息队列里来
//.....
//其他处理代码
}
return;
}
bool outMsgLULProc(int& command)
{
std::unique_lock<std::mutex> sbguard1(my_mutex);
if (!msgRecvQueue.empty())
{
//消息不为空
command = msgRecvQueue.front(); //返回第一个元素,但不检查元素是否存在;
msgRecvQueue.pop_front(); //移除第一个元素,但不返回;
return true;
}
return false;
}
//把数据从消息队列中取出的线程
void outMsgRecvQueue()
{
int command = 0;
for (int i = 0; i < 100; ++i)
{
bool result = outMsgLULProc(command);
if (result == true)
{
cout << "outMsgRecvQueue()执行了,从容器中取出一个元素" << command << endl;
//可以考虑进行命令(数据)处理
//....
}
else
{
//消息对列为空
cout << "outMsgRecvQueue()执行了,但目前收消息队列中是空元素" << i << endl;
}
}
cout << "end" << endl;
}
private:
std::list<int> msgRecvQueue; //容器(收消息队列),专门用于代表玩家给咱们发送过来的命令
std::mutex my_mutex; //创建互斥量
};
int main()
{
{
A myobja;
std::thread myOutnMsgObj(&A::outMsgRecvQueue, &myobja); //注意这里第二个参数必须是引用(用std::ref也可以),才能保证线程里用的是同一个对象
std::thread myInMsgObj(&A::inMsgRecvQueue, &myobja);
myInMsgObj.join();
myOutnMsgObj.join();
cout << "main主函数执行结束!" << endl;
}
return 0;
}
unique_lock的第二个参数
1、std::adopt_lock
使用std::adopt_lock的前提是开发者需要先把互斥量lock上。
#include<thread>
#include<iostream>
#include<list>
#include<mutex>
using namespace std;
class A
{
public:
//把收到的消息(玩家命令)入到一个队列的线程
void inMsgRecvQueue()
{
for (int i = 0; i < 100; ++i)
{
cout << "inMsgRecvQueue()执行,插入一个元素" << i << endl;
my_mutex.lock();
std::unique_lock<std::mutex> sbguard1(my_mutex, std::adopt_lock);
msgRecvQueue.push_back(i); //假设这个数字就是收到的命令,直接放到消息队列里来
//.....
//其他处理代码
}
return;
}
bool outMsgLULProc(int& command)
{
my_mutex.lock();
std::unique_lock<std::mutex> sbguard1(my_mutex, std::adopt_lock);
if (!msgRecvQueue.empty())
{
//消息不为空
command = msgRecvQueue.front(); //返回第一个元素,但不检查元素是否存在;
msgRecvQueue.pop_front(); //移除第一个元素,但不返回;
return true;
}
return false;
}
//把数据从消息队列中取出的线程
void outMsgRecvQueue()
{
int command = 0;
for (int i = 0; i < 100; ++i)
{
bool result = outMsgLULProc(command);
if (result == true)
{
cout << "outMsgRecvQueue()执行了,从容器中取出一个元素" << command << endl;
//可以考虑进行命令(数据)处理
//....
}
else
{
//消息对列为空
cout << "outMsgRecvQueue()执行了,但目前收消息队列中是空元素" << i << endl;
}
}
cout << "end" << endl;
}
private:
std::list<int> msgRecvQueue; //容器(收消息队列),专门用于代表玩家给咱们发送过来的命令
std::mutex my_mutex; //创建互斥量
};
int main()
{
{
A myobja;
std::thread myOutnMsgObj(&A::outMsgRecvQueue, &myobja); //注意这里第二个参数必须是引用(用std::ref也可以),才能保证线程里用的是同一个对象
std::thread myInMsgObj(&A::inMsgRecvQueue, &myobja);
myInMsgObj.join();
myOutnMsgObj.join();
cout << "main主函数执行结束!" << endl;
}
return 0;
}
2、std::try_to_lock
使用std::try_to_lock的前提是开发者不可以自己把互斥量lock上。
#include<thread>
#include<iostream>
#include<list>
#include<mutex>
using namespace std;
class A
{
public:
//把收到的消息(玩家命令)入到一个队列的线程
void inMsgRecvQueue()
{
for (int i = 0; i < 100; ++i)
{
cout << "inMsgRecvQueue()执行,插入一个元素" << i << endl;
//std::unique_lock<std::mutex> sbguard1(my_mutex, std::adopt_lock);
//std::unique_lock<std::mutex> sbguard1(my_mutex);
std::unique_lock<std::mutex> sbguard1(my_mutex, std::try_to_lock);
if (sbguard1.owns_lock()) //条件成立表示拿到了锁头
{
//拿到了锁头,离开sbguard1作用域锁头会自动释放
msgRecvQueue.push_back(i); //假设这个数字就是收到的命令,直接放到消息队列里来
//.....
//其他处理代码
}
else
{
//没拿到锁
cout << "inMsgRecvQueue()执行,但没拿到锁,只能干点别的事" << i << endl;
}
}
}
bool outMsgLULProc(int& command)
{
std::unique_lock<std::mutex> sbguard1(my_mutex);
std::chrono::milliseconds dura(20000); //定义一个时间相关对象,初值2万,单位毫秒, 卡在这里20秒
std::this_thread::sleep_for(dura);
if (!msgRecvQueue.empty())
{
//消息不为空
command = msgRecvQueue.front(); //返回第一个元素,但不检查元素是否存在;
msgRecvQueue.pop_front(); //移除第一个元素,但不返回;
return true;
}
return false;
}
//把数据从消息队列中取出的线程
void outMsgRecvQueue()
{
int command = 0;
for (int i = 0; i < 100000; ++i)
{
bool result = outMsgLULProc(command);
if (result == true)
{
cout << "outMsgRecvQueue()执行了,从容器中取出一个元素" << command << endl;
//可以考虑进行命令(数据)处理
//....
}
else
{
//消息对列为空
cout << "outMsgRecvQueue()执行了,但目前收消息队列中是空元素" << i << endl;
}
}
cout << "end" << endl;
}
private:
std::list<int> msgRecvQueue; //容器(收消息队列),专门用于代表玩家给咱们发送过来的命令
std::mutex my_mutex; //创建互斥量
std::mutex my_mutex2; //创建互斥量
};
int main()
{
{
A myobja;
std::thread myOutnMsgObj(&A::outMsgRecvQueue, &myobja); //注意这里第二个参数必须是引用(用std::ref也可以),才能保证线程里用的是同一个对象
std::thread myInMsgObj(&A::inMsgRecvQueue, &myobja);
myInMsgObj.join();
myOutnMsgObj.join();
cout << "main主函数执行结束!" << endl;
}
return 0;
}
3、std::defer_lock
使用defer_lock的前提是开发者不能自己吧互斥量lock上,否则会报异常
unique_lock的成员函数
1、lock
给互斥量加锁,如果无法拿到锁,会阻塞一直等待拿到锁。
//把收到的消息(玩家命令)入到一个队列的线程
void inMsgRecvQueue()
{
for (int i = 0; i < 100000; ++i)
{
cout << "inMsgRecvQueue()执行,插入一个元素" << i << endl;
std::unique_lock<std::mutex> sbguard1(my_mutex, std::defer_lock);
sbguard1.lock(); //反正unique_lock能自动解锁,不用自己解,所以这里只管加锁
msgRecvQueue.push_back(i);
}
}
2、unlock
针对加锁的互斥量,给该互斥量解锁,不可以针对没加锁的互斥量使用,否则会报异常。
3、try_lock
尝试给互斥量加锁,如果拿不到锁,则返回false;如果拿到了锁,则返回true。这个成员函数不阻塞。
//把收到的消息(玩家命令)入到一个队列的线程
void inMsgRecvQueue()
{
for (int i = 0; i < 100000; ++i)
{
cout << "inMsgRecvQueue()执行,插入一个元素" << i << endl;
std::unique_lock<std::mutex> sbguard1(my_mutex, std::defer_lock);
if (sbguard1.try_lock() == true) //返回true表示拿到了锁,自己不用管unlock问题
{
msgRecvQueue.push_back(i);
}
else
{
cout << "抱歉,没拿到锁,做点别的事情吧!" << endl;
}
}
}
4、release
//把收到的消息(玩家命令)入到一个队列的线程
void inMsgRecvQueue()
{
for (int i = 0; i < 100000; ++i)
{
cout << "inMsgRecvQueue()执行,插入一个元素" << i << endl;
std::unique_lock<std::mutex> sbguard1(my_mutex); //mutex锁定
std::mutex* p_mtx = sbguard1.release(); //现在关联关系解除,程序员有责任自己解锁了,其实这个就是my_mutex,现在sbguard1已经不和my_mutex关联了(可以设置断点并观察)
msgRecvQueue.push_back(i);
p_mtx->unlock();//因为前面已经加锁,所以这里要自己解锁了
}
return;
}