一:unique_lock取代lock_guard
unique_lock是个类模板,工作中,一般使用lock_guard;lock_guard取代了mutex的lock()和unlock()
unique_lock比lock_guard灵活很多,虽然效率上差一点,内存占用多一点
二:unique_lock的第二个参数
- std::adopt_lock:表示这个互斥量已经被lock了(你必须把互斥量提前lock了,否则会报异常)
std::adopt_lock标记的效果就是“假设调用方线程已经拥有了互斥的所有权(已经lock()成功了)"
通知lock_guard不需要在构造函数中lock这个互斥量了;
用adopt_lock的前提是,你自己需要先把mutex先lock上
eg:
std::unique_lock<mutex> abguard1(my_mutex1,std::adopt_lock);
此时如果需要调用这条语句,则需要提前加锁,这条语句提供解锁功能。
- std::try_to_lock
我们会尝试用mutex的lock()去锁定这个mutex,但如果没有锁定成功,我也会立即返回,并不会阻塞在那里
用这个try_to_lock的前提是你自己不能先去lock
eg:
std::unique_lock<mutex> abguard1(my_mutex1, std::try_to_lock);
即当有两个线程时,如果一个锁住的时间较长,另一个线程碰到这个锁的时候,可以用if语句跳过这个锁,往后面执行
- std::defer_lock
用这个std::defer_lock的前提是,你不能自己先lock,否则会报异常
defer_lock的意思就是并没有给mutex加锁,初始了一个没有加锁的mutex
使用std::defer_lock设置初始化的时候不进行默认的上锁操作;从而在使用时可以随时加锁和解锁,而且最后一个锁不用进行解锁。
三,unique_lock的成员函数
- lock(),加锁
- unlock(),解锁
- try_lock(),尝试去拿到锁,返回true则拿到锁
- release(),返回它所管理的mutex对象指针,并释放所有权,也就是说unique_lock和mutex不在有关系
严格区分unlock()和release()的区别
如果原来mutex对象处于加锁状态,则需要接管过来并且解锁。(release返回的是原视my_mutex的指针)
eg:
std::unique_lock<mutex> abguard1(my_mutex1);
此时ptr就是my_mutex1的指针
mutex *ptr=abguard1.release(); //现在需要自己解锁my_mutex1
ptr->unlock();
注:
lock锁住的代码越少,执行越快,整个程序运行效率越高
把锁头锁住的代码多少称为粒度,粒度一般用粗细进行表示
a)锁住的代码越少,这个粒度越细,执行效率越高
a)锁住的代码越多,这个粒度越粗,执行效率越低
四,unique_lock所有权的传递mutex
unique_lock<mutex> abguard1(my_mutex1); //所有权问题
abguard1可以把自己对mutex(my_mutex1)的所有权给其他unique_lock对象
使用move,但是只能转移,不能复制
#include<iostream>
#include<vector>
#include<thread>
#include<list>
#include<mutex>
using namespace std;
class A
{
public:
void inMsgRecvQueue()
{
for (int i = 0; i < 10000; ++i)
{
cout << "inMsgRecvQueue()执行,插入一个元素" << i << endl;
//std::unique_lock<mutex> abguard1(my_mutex1,std::adopt_lock);
//std::unique_lock<mutex> abguard1(my_mutex1, std::try_to_lock);
//if (abguard1.owns_lock())
//{
std::unique_lock<mutex> abguard1(my_mutex1, std::defer_lock); //没有加锁的abguard1
abguard1.lock(); //不用自己unlock
//处理一些非共享的代码时,先unlock,然后再lock()
//abguard1.unlock();
//处理非共享代码
//.......
//abguard1.lock(); //这个lock不用再unlock,上面的unique_lock会帮助解锁
msgRecvQueue.push_back(i); //把收到的命令,放到消息队列中
//}
}
}
bool outMsgLUL(int &command)
{
std::unique_lock<mutex> abguard1(my_mutex1);
//此时ptr就是my_mutex1的指针
//mutex *ptr=abguard1.release(); //现在需要自己解锁my_mutex1
//ptr->unlock();
if (!msgRecvQueue.empty())
{
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
return true;
}
return false;
}
//把数据从消息队列中取出的线程
void outMsgRecvRueue()
{
int command = 0;
for (int i = 0; i < 100000; ++i)
{
bool YN = outMsgLUL(command);
if (YN)
{
cout << "outMsgRecvQueue()执行,取出一个元素" << command << endl;
//可以考虑进行命令(数据)处理
//....
}
else
{
//消息队列为空
cout << "outMsgRecvQueue()执行,但是目前消息队列为空" << i << endl;
}
}
}
private:
list<int> msgRecvQueue;
mutex my_mutex1; //创建一个互斥量
};
int main()
{
A a;
thread test1(&A::outMsgRecvRueue, &a);//第二个参数是引用才能保证
thread test2(&A::inMsgRecvQueue, &a);//第二个参数是引用才能保证
test1.join();
test2.join();
//一:unique_lock取代lock_guard
//unique_lock是个类模板,工作中,一般使用lock_guard;lock_guard取代了mutex的lock()和unlock()
//unique_lock比lock_guard灵活很多,效率上差一点,内存占用多一点
//二:unique_lock的第二个参数
//(2.1)std::adopt_lock:表示这个互斥量已经被lock了(你必须把互斥量提前lock了,否则会报异常)
//std::adopt_lock标记的效果就是“假设调用方线程已经拥有了互斥的所有权(已经lock()成功了)"
//通知lock_guard不需要在构造函数中lock这个互斥量了;
//用adopt_lock的前提是,你自己需要先把mutex先lock上
//(2.2)std::try_to_lock
//我们会尝试用mutex的lock()去锁定这个mutex,但如果没有锁定成功,我也会立即返回,并不会阻塞在那里
//用这个try_to_lock的前提是你自己不能先去lock
//(2.3)std::defer_lock
//用这个std::defer_lock的前提是,你不能自己先lock,否则会报异常
//defer_lock的意思就是并没有给mutex加锁,初始了一个没有加锁的mutex
//
//三,unique_lock的成员函数
//(3.1)lock(),加锁
//(3.2)Unlock(),解锁
//(3.3)try_lock(),尝试去拿到锁,返回true则拿到锁
//(3.4)release(),返回它所管理的mutex对象指针,并释放所有权,也就是说unique_lock和mutex不在有关系
//严格区分unlock()和release()的区别
//如果原来mutex对象处于加锁状态,则需要接管过来并且解锁。(release返回的是原视my_mutex的指针)
// lock锁住的代码越少,执行越快,整个程序运行效率越高
//把锁头锁住的代码多少称为粒度,粒度一般用粗细进行表示
//a)锁住的代码越少,这个粒度越细,执行效率越高
//a)锁住的代码越多,这个粒度越粗,执行效率越低
//四,unique_lock所有权的传递mutex
//unique_lock<mutex> abguard1(my_mutex1); //所有权问题
//abguard1可以把自己对mutex(my_mutex1)的所有权给其他unique_lock对象
//使用move,但是只能转移,不能复制
system("pause");
return 0;
}