一、unique_lock取代lock_guard
是个类模板,一般用lock_guard,unique_guard更灵活,效率差一点,内存占用多了一点。
二、unique_lock 的第二个参数
1、std::adopt_lock
就是个标记,表示位于第一个参数的互斥量已经lock了。(你必须先把这个互斥量lock,否则会报异常)
2、std::try_to_lock
正常情况下线程A锁住一个mutex,然后要求等待10秒,这个时候另一个线程B要锁这个mutex,但是由于线程A没有解锁这个mutex,那么线程B相当于也要等至少10秒钟,会卡在这里,等A解锁了这个mutex才能去拿这个锁。对于这种情况,unique_lock就能够灵活的处理。
unique_lock的try_to_lock参数会尝试用mutex的lock()去锁住这个mutex,但如果没有锁定成功,也会立即返回,并不会阻塞在那里。(前提是你自己不能先去lock)
1 void InMsgQue(){ 2 for(int i=0;i<100;i++){ 3 cout<<"InMsgQue执行,插入一个元素"<<i<<endl; 4 std::unique_lock<std::mutex> my_lock(my_mutex1,std::try_to_lock); 5 if(my_lock.owns_lock()){//判断是否拿到了锁 6 //拿到了锁。。。。。 7 } 8 else{ 9 //没拿到锁的话要做的事情 10 } 11 MyQue.push_back(i);//假设i就是命令 12 //其他处理代码、、、、、、、 13 } 14 }
3、std::defer_lock
前期:不能自己先去lock
并没有给mutex加锁,初始化了一个没有加锁的mutex,这样就方便里调用一些unique_lock的一些成员函数。
1 void InMsgQue(){ 2 for(int i=0;i<100;i++){ 3 cout<<"InMsgQue执行,插入一个元素"<<i<<endl; 4 std::unique_lock<std::mutex> my_lock(my_mutex1,std::defer_lock);//没有枷锁的mutex,相当于将my_mutex1和my_lock绑定一起了 5 my_lock.lock();//不用自己unlock 6 if(my_lock.owns_lock()){//判断是否拿到了锁 7 //拿到了锁。。。。。 8 } 9 else{ 10 //没拿到锁 11 } 12 MyQue.push_back(i);//假设i就是命令 13 //其他处理代码、、、、、、、 14 } 15 }
三、unique_lock成员函数
1、lock
2、unlock
配合defer_lock参数
unique_lock可以自己unlock了,为什么还要有unlock这个成员函数?
void InMsgQue(){ for(int i=0;i<100;i++){ cout<<"InMsgQue执行,插入一个元素"<<i<<endl; std::unique_lock<std::mutex> my_lock(my_mutex1,std::defer_lock);//没有枷锁的mutex,相当于将my_mutex1和my_lock绑定一起了 my_lock.lock();//不用自己unlock //有时候有一些非共享代码要去处理,所以先unlock my_lock.unlock(); //接着处理一些共享代码 my_lock.lock();
//其他处理代码.......
//my_lock.unlock();//画蛇添足,unique_lock的析构函数会unlock,但是也不会出问题
}
为什么有时候需要unlock()?
因为lock锁住的代码越少,执行越快,整个程序运行效率就越高。
有人也把锁住的代码多少称为锁的粒度,粒度一般用粗细来秒速。
锁住的代码少,粒度细,执行效率高;
锁住的代码高,粒度粗,执行效率低;
要尽量选择合适的粒度,粒度太细,可能漏掉对共享数据的保护,粒度太粗,影响效率。
3、try_lock
配合defer_lock使用。
1 void InMsgQue(){ 2 for(int i=0;i<100;i++){ 3 cout<<"InMsgQue执行,插入一个元素"<<i<<endl; 4 std::unique_lock<std::mutex> my_lock(my_mutex1,std::defer_lock);//没有枷锁的mutex,相当于将my_mutex1和my_lock绑定一起了 5 if(my_lock.try_lock()==true){ 6 //如果拿到锁了。。。。。 7 } 8 else{ 9 //如果没拿到所 10 } 11 } 12 }
4、release
返回它管理的mutex对象指针,释放所有权,也就是这个unique_lock和mutex不再有关系。
和unlock不同的,不要混淆。
1 void InMsgQue(){ 2 for(int i=0;i<100;i++){ 3 std::unique_lock<std::mutex> my_lock(mutex1); 4 std::mutex *ptx = my_lock.release();//断开my_lock和mutex1的关系,所以你要自己解锁了 5 ptx->unlock();//自己负责mutex1的unlock 6 cout<<"InMsgQue执行,插入一个元素"<<i<<endl; 7 } 8 }
四、unique_lock所有权的传递
一个unique_lock要只和一个mutex绑定在一起,也就是一个unique_lock只管理一个mutex。
my_lock也就是拥有mutex1的所有权。
my_lock可以把自己对mutex1的所有权 是属于可以转移,不能复制。
unique_lock也可以作为函数定义时的返回类型的:
1 std::unique_lock<std::mutex> my_lock(){ 2 std::unique_lock<std::mutex> temp_lock(mutex1); 3 return temp_lock; 4 } 5 std::unique_lock<std::mutex> new_lock = my_lock();