
一、unique_lock取代lock_guard
-
unique_lock可以完全取代lock_guard -
unique_lock是一个类模板,比lock_guard灵活,但是效率差一些
二、unique_lock的第二个参数
2.1 std::adopt_lock参数
- 该参数表示这个当前这个互斥量
mutex已经被lock了,那么就不要再调用ctor中的lock()函数了,只调用析构函数中的unlock()就好。
要先给mutex加上lock,然后才能调用unique_lock中的adopt_lock参数
2.2 std::try_to_lock
因为in线程和out线程都有可能先被调用,我们在out线程加了一段代码,让其等待20s,也就是给my_mutex1加上lock以后,等待了20S,这样会导致in线程拿不到mymutex也跟着等待20S,所以我们引入了try_to_lock。
但是和adopt_lock不同的是,try_to_lock使用的时候一定不能先lock(),不然就会直接卡住——
卡住
然后报错
异常
因为我们引用try_to_lock的意义是,当我们使用lock去锁定mutex的时候,如果没有锁定成功,会立即返回,而不是阻塞(等待)在那里。
所以用
try_to_lock的时候一定不能先去lock。
try_to_lock的意思是尝试加锁它的好处就是——当线程A拿不到锁的时候,线程A不会等在那里,它会去做一些别的事情
2.3 defer_lock
使用defer_lock的前提是——不能自己先lock,不然会有异常。(跟try_to_lock一样)
defer_lock并没有给mutex加锁
- 初始化了
一个没有加锁的mutex(从而增加了灵活性)
三、unique_lock的成员函数
3.1 lock()
- 加锁
3.2 unlock()
- 解锁
因为只有共享代码需要加锁,然后解锁,非共享代码是不需要的。
所以上述中,我们先用了defer_lock,然后调用了lock(),并没有调用unlock(),这样会导致有一部分非共享代码此时是被锁住的,也就不能执行的,但是锁住非共享代码是没必要的,所以我们可以调用unlock(),从而让非共享代码可以及时处理。当我们处理完这些非共享代码后,可以再调用lock()函数对共享代码进行上锁。
unique_lock()的灵活性和稳定性体现在2点——
- 可以随时处理
共享或者非共享的代码 - 上锁后如果不着急处理
非共享的代码,可以只调用一个lock()
defer_lock的使用相当于将go_guard1和unique_lock和mutex三者绑定在了一起
lock是给unique_lock绑定的mutex加锁
3.3 try_lock()
尝试给互斥量加锁
- 如果拿不到锁,则返回false
- 如果拿到了锁,则返回true
- 这个函数是不阻塞的
3.4 relese()
返回管理的Mutex对象指针, 并释放所有权,从而实现unique_lock和mutex不再有关系。
本来是把unique_lock和mutex绑定在一起,relese就是把它俩分开了(好残忍呀~),也就是说,relese是放弃了unique_lock和mutex之间的关系。
所以说,如果之前mutex对象属于加锁状态,那么relese后,我需要负责
解锁
release返回的是原始的mutex指针,代码中的是
*ptx,对应的就是mutex对象。
3.5 锁的粒度
- 锁头锁住的代码的多少称为粒度
- 锁住的代码少,粒度就比较细,程序的运行效率就高
- 锁住的代码多,粒度就比较粗,程序的运行效率就低
四、unique_lock的所有权的传递
std::unique_lock<std::mutex> go_guard1(my_mutex1);
可以说go_guard1拥有my_mutex1的所有权
go_guard1可以把自己对mutex的所有权转移给其他的unique_lock对象,比如go_guard2。
unique_lock对象对于mutex的所有权是属于
可以转移,但是不能复制。转移的话使用move
std::unique_lock<std::mutex> go_guard2(std::move(go_guard1));
转移的话也可以使用函数的临时对象——
return rtn_unique_lock()
源代码
- try_to_lock
#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::lock(my_mutex1, my_mutex2); // 要先给mutex加上lock
// 然后才能调用unique_lock中的adopt_lock参数
/*my_mutex1.lock();
std::unique_lock<std::mutex> go_guard1(my_mutex1, std::adopt_lock);*/
std::unique_lock<std::mutex> go_guard1(my_mutex1, std::try_to_lock);
if (go_guard1.owns_lock()) msgRecvQueue.push_back(i);
else cout << "inMsgRecvQueue()执行,但是没有拿到锁" << i << endl;
}
return;
}
bool outMsgLULProc(int& command)
{
std::unique_lock<std::mutex> go_guard1(my_mutex1);
std::chrono::milliseconds dura(200);
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 < 10000; i++)
{
bool res = outMsgLULProc(command);
if (res == true) cout << "outMsgRecvQueue执行,取出一个元素" << command << endl;
else cout << "outMsgRecvQueue()执行,但是目前消息队列中为空" << i << endl;
}
cout << "end" << endl;
}
private:
std::list<int> msgRecvQueue;
std::mutex my_mutex1;
std::mutex my_mutex2;
};
int main()
{
A myobj_a;
std::thread myOutMsgObj(&A::outMsgRecvQueue, &myobj_a);
std::thread myInMsgObj(&A::inMsgRecvQueue, &myobj_a);
myInMsgObj.join();
myOutMsgObj.join();
}
- unique_lock的lock()函数
#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<std::mutex> go_guard1(my_mutex1, std::defer_lock); // 没有加锁的mutex
go_guard1.lock(); // 不用自己unlock,因为unique_lock是智能的
// 而且这个lock()函数是guard调用的,不是mutex调用的
msgRecvQueue.push_back(i);
}
return;
}
bool outMsgLULProc(int& command)
{
std::unique_lock<std::mutex> go_guard1(my_mutex1);
std::chrono::milliseconds dura(200);
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 < 10000; i++)
{
bool res = outMsgLULProc(command);
if (res == true) cout << "outMsgRecvQueue执行,取出一个元素" << command << endl;
else cout << "outMsgRecvQueue()执行,但是目前消息队列中为空" << i << endl;
}
cout << "end" << endl;
}
private:
std::list<int> msgRecvQueue;
std::mutex my_mutex1;
std::mutex my_mutex2;
};
int main()
{
A myobj_a;
std::thread myOutMsgObj(&A::outMsgRecvQueue, &myobj_a);
std::thread myInMsgObj(&A::inMsgRecvQueue, &myobj_a);
myInMsgObj.join();
myOutMsgObj.join();
}
- defer_lock的成员函数lock()和unlock()并用
#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<std::mutex> go_guard1(my_mutex1, std::defer_lock); // 没有加锁的mutex
go_guard1.lock(); // 不用自己unlock,因为unique_lock是智能的
// 而且这个lock()函数是guard调用的,不是mutex调用的
go_guard1.unlock();
go_guard1.lock();
msgRecvQueue.push_back(i);
}
return;
}
bool outMsgLULProc(int& command)
{
std::unique_lock<std::mutex> go_guard1(my_mutex1);
if (!msgRecvQueue.empty())
{
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
return true;
}
return false;
}
void outMsgRecvQueue()
{
int command = 0;
for (int i = 0; i < 10000; i++)
{
bool res = outMsgLULProc(command);
if (res == true) cout << "outMsgRecvQueue执行,取出一个元素" << command << endl;
else cout << "outMsgRecvQueue()执行,但是目前消息队列中为空" << i << endl;
}
cout << "end" << endl;
}
private:
std::list<int> msgRecvQueue;
std::mutex my_mutex1;
std::mutex my_mutex2;
};
int main()
{
A myobj_a;
std::thread myOutMsgObj(&A::outMsgRecvQueue, &myobj_a);
std::thread myInMsgObj(&A::inMsgRecvQueue, &myobj_a);
myInMsgObj.join();
myOutMsgObj.join();
}
- try_lock()
#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<std::mutex> go_guard1(my_mutex1, std::defer_lock); // 没有加锁的mutex
if (go_guard1.try_lock()) msgRecvQueue.push_back(i);
else cout << "inMsgRecvQueue()执行,但是没有拿到锁,只能做一些别的事情" << i << endl;
}
return;
}
bool outMsgLULProc(int& command)
{
std::unique_lock<std::mutex> go_guard1(my_mutex1);
if (!msgRecvQueue.empty())
{
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
return true;
}
return false;
}
void outMsgRecvQueue()
{
int command = 0;
for (int i = 0; i < 10000; i++)
{
bool res = outMsgLULProc(command);
if (res == true) cout << "outMsgRecvQueue执行,取出一个元素" << command << endl;
else cout << "outMsgRecvQueue()执行,但是目前消息队列中为空" << i << endl;
}
cout << "end" << endl;
}
private:
std::list<int> msgRecvQueue;
std::mutex my_mutex1;
std::mutex my_mutex2;
};
int main()
{
A myobj_a;
std::thread myOutMsgObj(&A::outMsgRecvQueue, &myobj_a);
std::thread myInMsgObj(&A::inMsgRecvQueue, &myobj_a);
myInMsgObj.join();
myOutMsgObj.join();
}
- relese()
void inMsgRecvQueue()
{
for (int i = 0; i < 10000; i++)
{
cout << "inMsgRecvQueue()执行,插入一个元素" << i << endl;
std::unique_lock<std::mutex> go_guard1(my_mutex1);
std::mutex* ptx = go_guard1.release();
msgRecvQueue.push_back(i);
ptx->unlock();
}
return;
}
- 所有权转移
void inMsgRecvQueue()
{
for (int i = 0; i < 10000; i++)
{
cout << "inMsgRecvQueue()执行,插入一个元素" << i << endl;
std::unique_lock<std::mutex> go_guard1(my_mutex1);
std::unique_lock<std::mutex> go_guard2(std::move(go_guard1));
msgRecvQueue.push_back(i);
}
return;
}
- return unique_lock临时对象
class A
{
public:
// 从函数返回一个局部的unique_lock对象是可以的,返回局部对象会让系统生成一个临时unique_lock对象
// 并调用unique_lock的移动构造函数
std::unique_lock<std::mutex> rtn_unique_lock()
{
std::unique_lock<std::mutex> tmpguard(my_mutex1);
return tmpguard;
}
void inMsgRecvQueue()
{
for (int i = 0; i < 10000; i++)
{
cout << "inMsgRecvQueue()执行,插入一个元素" << i << endl;
std::unique_lock<std::mutex> go_guard1 = rtn_unique_lock();
msgRecvQueue.push_back(i);
}
return;
}
...
}

