unique_lock 是一个类模板。
unique_lock 比 lock_guard 灵活很多(多出来很多用法),效率差一点,内存占用多一些。
使用:
unique_lock
std::adopt_lock:标记作用,表示这个互斥量已经被lock()(方便记忆:已经被lock()收养了,不需要再次lock() ),即不需要在构造函数中lock这个互斥量了。
前提:必须提前lock,否则会出错
lock_guard中也可以用这个参数
bool outMsgProc(int &num)
{
unique_lock<mutex> muGuard(myMutex1);
chrono::milliseconds time(2000); //线程暂停2s
this_thread::sleep_for(time);
if (!myList.empty())
{
num = myList.front();
myList.pop_front();
return true;
}
return false;
}
在此期间,如果线程2也尝试锁定myMutex1,就只能阻塞,直到线程1释放锁后,才能继续执行。线程2执行的代码如下:
void InMsg()
{
for (int i = 0; i < 10000; i++)
{
cout << "插入元素: " << i << endl;
unique_lock<mutex> muGuard(myMutex1);
myList.push_back(i);
}
}
显然,这样的程序效率不高。线程2花费了太多的时间等待。
我们考虑使用try_to_lock,线程尝试获取锁,如果没有锁定成功,它不会阻塞在那里,可以去执行其他代码。改进后的代码如下:
void InMsg()
{
for (int i = 0; i < 10000; i++)
{
cout << "插入元素: " << i << endl;
unique_lock<mutex> muGuard(myMutex1, try_to_lock);
if (muGuard.owns_lock())// 判断是否拿到锁
{
myList.push_back(i);
}
else
{
//没有拿到锁时,执行的代码
}
}
}
unique_lock<mutex> muGuard(myMutex, defer_lock);
muGuard.lock();//手动加锁
不用自己unlock();
unique_lock<mutex> muGuard(myMutex, defer_lock);
muGuard.lock();
//处理一些共享代码
muGuard.unlock();
//临时处理一些非共享代码
muGuard.lock();
//处理一些共享代码,处理完之后,自动解锁
try_to_lock是unique_lock的第二个参数,try_lock()是unique_lock()的成员变量。
如果拿不到锁,返回false,否则返回true(然后上锁)。
unique_lock<mutex>muGuard(myMutex, defer_lock);
//mutex1.lock();//自动解锁
if (muGuard.try_lock() == true) {
cout << "插入数据: " << num << endl;
test_list.push_back(num);
}
else {
cout << "in_list()执行,但没有拿到锁" << num << endl;
}
release():就是解除绑定,返回它所管理的mutex对象的指针,并释放所有权。
unique_lockmuGuard(myMutex1);
mutex* ptx =muGuard.release();
for (int num = 0; num < 10000; num++) {
unique_lock<mutex> muGuard(myMutex);
mutex* ptx = muGuard.release();//解除myMutex1(mutex对象)和 muGuard绑定
//操作事务
test_list.push_back(num);
ptx->unlock();//myMutex1所有权由ptx接管,由ptx进行解锁
}
lock的代码段越少,执行越快,整个程序的运行效率越高。
unique_lock
把myMutex1和muGuard绑定在了一起,也就是muGuard拥有myMutex1的所有权
unique_lock
之前muGuard1拥有myMutex的所有权,muGuard1可以把自己对myMutex的所有权转移,但是不能复制。现在muGuard2拥有myMutex的所有权。
unique_lock<mutex> aFunction()
{
unique_lock<mutex> tmpguard(myMutex);
//移动构造函数那里讲从函数返回一个局部的unique_lock对象是可以的
//返回这种局部对象会导致系统生成临时的unique_lock对象,并调用unique_lock的移动构造函数
return tmpguard;
}
// 然后就可以在外层调用,在muGuard2具有对myMutex的所有权
std::unique_lock<std::mutex> muGuard2 = aFunction();