unique_lock取代lock_guard
unique_lock是一个类模板,比lock_guard更加灵活,效率上低一点,内存占用大一点
首先是unique_lock可以直接替换lock_guard,调用unique_lock也不需要手动解锁。
std::lock_guard<std::mutex>myguard1(my_mutex1);
和
std::unique_lock<std::mutex>myguard1(my_mutex1);
的效果是一样的。
unique_lock可以带第二个参数
unique_lock的第二个参数
std::adopt_lock
unique_lock和lock_guard的adopt_lock参数含义相同
表示互斥量已经被lock了(必须要把互斥量提前lock,否则会报异常)
效果就是该线程已经拥有了互斥量的所有权(已经lock成功),通知lock_guard不需要在构造函数中lock这个互斥量
std::try_to_lock
std::unique_lock<std::mutex>myguard1(my_mutex1, std::try_to_lock);
执行过这句话之后(在这句话之前不能先使用lock),我们通过owns_lock()判断来进行下一步操作,不会卡在此处,如果其他线程持续占用该互斥量锁,那么该线程就不会持续等待。
std::unique_lock<std::mutex>myguard1(my_mutex1,std::try_to_lock);
if (myguard1.owns_lock())
{
cout << "inMsgRecvQueue执行插入一个元素" << i << endl;
msgRecvQueue.push_back(i);
}
else
{
cout << "inMsgRecvQueue执行了,但是没有拿到锁\n" << i << endl;
}
std::defer_lock
作用是初始化一个没有加锁的mutex(在使用其他参数时会在创建mutex时直接尝试加锁)
可以借着defer_lock来介绍一些unique_lock的成员函数
unique_lock的成员函数
成员函数lock()
std::unique_lock<std::mutex>myunique_lock(my_mutex1,std::defer_lock);//创建一个没有加锁的myunique_lock
myunique_lock.lock();//对myunique_lock进行加锁操作
对于没有加锁的myunique_lock,可以通过成员函数myunique_lock.lock()进行上锁。
成员函数unlock()
对于上锁的myunique_lock,可以通过unlock()提前解锁来运行一些不需要共享数据的代码,这使得我们的代码设计更加灵活。
std::unique_lock<std::mutex>myunique_lock(my_mutex1,std::defer_lock);//创建一个没有加锁的myunique_lock
myunique_lock.lock();//对myunique_lock进行加锁操作
//处理一些共享数据代码
myunique_lock.unlock();
//继续处理一些非共享代码
//。。。。。。
//处理完之后可以再次上锁
myunique_lock.lock();//对myunique_lock进行加锁操作
为什么要使用unlock():
有人也把锁头锁住的代码多少称为锁的粒度,粒度一般用粗细来描述
- 锁住的代码越少,这个锁的粒度就细,执行效率就越高
- 锁住的代码越多,这个锁的粒度就粗,执行效率就越低
要选择合适粒度的代码来上锁!
成员函数try_lock()
类似于参数std::try_to_lock,在不阻塞的情况下进行lock,如果加锁成功,那么返回true,如果没有加锁成功,那么返回false。
std::unique_lock<std::mutex>myunique_lock(my_mutex1,std::defer_lock);//创建一个没有加锁的myunique_lock
if(myunique_lock.try_lock())
{
//上锁成功,进行数据处理
}
成员函数release()
通过release()会返回它所管理的mutex对象指针,并释放所有权(也就是说,这个unique_lock和mutex不再有关系)
要区分开release()和unlock()。
release()之后要负责把上锁的mutex解锁,否则会报错。
std::unique_lock<std::mutex>myunique_lock(my_mutex1,std::defer_lock);//创建一个没有加锁的myunique_lock
myunique_lock.lock();//对myunique_lock进行加锁操作
//处理一些共享数据代码
std::mutex *ptr = myunique_lock.release();//释放myunique_lock并返回my_mutex1的指针
//处理共享数据
ptr->unlock();//手动解锁,如果不解锁会卡住导致程序崩溃
unique_lock所有权的传递(转移)
一般来说,unique_lock和mutex是绑定在一起的,是通过unique_lock来管理mutex。
所有权概念:
std::unique_lock<std::mutex>myunique_lock(my_mutex1);
表示myunique_lock拥有my_mutex1的所有权,可以把该所有权转移给其他的unique_lock对象。
可以通过move来转移所有权
std::unique_lock<std::mutex>myunique_lock(my_mutex1,std::defer_lock);//创建一个没有加锁的myunique_lock
std::unique_lock<std::mutex>myunique_lock2(std::move(myunique_lock));//将myunique_lock所有的my_mutex1转移给myunique_lock2
也可以通过return来返回unique_lock
std::unique_lock<std::mutex> rtn_unique_lock()
{
std::unique_lock<std::mutex> tmpguard(my_mutex1);
return tmpguard;//从函数返回一个局部的unique_lock对象是可以的
//返回这种局部对象tmpguard会导致系统生成临时的unique_lock对象,并调用unique_lock的移动构造函数
}
然后调用这个rtn_unique_lock()函数来转移移动构造函数的所有权
std::unique_lock<std::mutex> myunique_lock2 = rtn_unique_lock();
此时myunique_lock2 就是互斥量my_mutex1的一个unique_lock对象。