C++并发与多线程(五) unique_lock用法

本文详细解析unique_lock类模板,探讨其用法、参数如adopt_lock、try_to_lock、defer_lock,以及lock/unlock/try_lock/release等方法。重点讲解所有权传递和std::move在unique_lock中的应用。

unique_lock

unique_lock是一个类模板,可以完全取代lock_guard;

它的灵活性比lock_guard高很多,但是相对的,他的效率,内存的占用要高一些。

用法同lock_guard():

unique_lock< mutex > myUnique(mutex);

unique_lock的第二个参数

std::adopt_lock

  1. 这个参数表示这个互斥量已经被lock(),即不需要在构造函数中lock这个互斥量了。
  2. 使用的前提,是线程已经调用了lock(),属于已经lock的状态
  3. adopt_lock参数的效果就是“假设调用线程已经取得了互斥的所有权”,如果已经lock,那么构造函数中就不会再调用lock()了。

用法:

mutex mutex1;
mutex1.lock(); //adopt_lock的前提是线程必须先lock(),否则会报错
std::unique_lock<std::mutex> myUnique(mutex1, adopt_lock); //用法同lock_guard的adopt_lock参数

std::try_to_lock

  1. 尝试用mutx的lock()去锁定这个mutex,但如果没有锁定成功,会立即返回,不会阻塞在那里;
  2. 使用try_to_lock的前提是,没有提前lock();
  3. 使用try_to_lock的原因是防止其他的线程锁定mutex太长时间,导致本线程一直阻塞在lock这个地方;
  4. owns_locks()方法可以判断是否拿到锁,返回值为true or false;
mutex mutex1;
//mutex1.lock(); //try_to_lock参数的前提是不可以提前lock()
std::unique_lock<std::mutex> myUnique(mutex1, try_to_lock); //unique_lock的try_to_lock参数用法

if(myUnique.owns_locks()){
	//拿到了锁
}
else{
	//未拿到锁
}

std::defer_lock

  1. defer_lock参数是始化了一个没有加锁的mutex(因为我们知道,对于没有第二个参数的unique_lock是默认对mutex进行加锁的)
  2. 使用defer_lock的前提是,没有提前lock();
  3. 不给它加锁的目的是以后可以调用unique_lock的一些方法

用法:

mutex mutex1;
//mutex1.lock(); //try_to_lock参数的前提是不可以提前lock()
std::unique_lock<std::mutex> myUnique(mutex1,defer_lock); //创建一个没有加锁的mutex1
//后续可以调用unique_lock的一些方法
myUnique.lock();//加锁,不需要unlock(),会析构的时候自动unlock();

unique_lock成员函数

lock()方法

unique_lock的lock()方法,手动加锁,自动解锁(析构的时候自动调用unlock()),unique_lock引入lock方法的意义是增加灵活性,不是一定要在定义unique_lock的时候自动调用lock()(构造函数默认调用lock())。

mutex mutex1;
//mutex1.lock(); //try_to_lock参数的前提是不可以提前lock()
std::unique_lock<std::mutex> myUnique(mutex1,defer_lock); //创建一个没有加锁的mutex1

myUnique.lock();//加锁,不需要unlock(),会析构的时候自动unlock();

unlock()方法

unlock():解锁,默认调用了lock()就会在析构的时候自动调用unlock;

引入unlock()的目的也是为了增加灵活性,有可能我们在析构之前,需要对互斥量进行访问,这时候就需要我们手动unlock处理完毕后,再lock

lock住的代码段越少,执行越快,整个程序运行效率高,有人也把锁头锁住的代码多少称为锁的粒度,粒度一般用粗细来描述;

a)锁住的代码少,粒度细,执行效率高
b)锁住的代码多,粒度粗,执行效率低

要尽量选择适合粒度的代码进行保护,粒度太细可能漏掉共享数据的保护,粒度太粗,影响效率。

mutex mutex1;
std::unique_lock<std::mutex> myUnique(mutex1, defer_lock);//创建一个没有加锁的mutex1
myUnique.lock(); //手动lock
//处理一些共享代码
myUnique.unlock(); //手动unlock
//处理一些非共享代码
myUnique.lock(); //处理完毕,再手动lock
//处理一些共享代码

try_lock()方法

try_lock尝试给互斥量加锁,返回true or false,与owns_locks()比较类似,这个函数是不阻塞的。

mutex mutex1;
std::unique_lock<std::mutex> myUnique(mutex1, defer_lock);//创建一个没有加锁的mutex1

if(myUnique.try_lock()){
	//拿到了锁
}
else{
	//未拿到锁
}

release()方法

  1. release方法返回它所管理的mutex对象指针,并释放所有权;也就是说unique_lock和mutex不再有关系;
  2. 区分release和unlock,release之后如果原来mutex对象处于加锁状态,需要接管过来并负责解锁;
  3. release()返回值是一个mutex指针,需要用一个mutex*来接收。
mutex mutex1;
std::unique_lock<std::mutex> myUnique(mutex1, defer_lock);//创建一个没有加锁的mutex1

std::mutex *ptx = myUnique.release();//ptx指向现在的mutex1,需要自己手动unlock
ptx->unlock();

unique_lock所有权的传递

std::unique_lock<std::mutex> myUnique(mutex1, defer_lock);

  1. myUnique拥有mutex1的所有权;
  2. myUnique可以把自己对mutex(mutex1)的所有权转移给其他的unique_lock对象;
  3. unique_lock对象这个mutex的所有权是属于可以移动不能复制的,因为一个unique_lock对象只能对应一个mutex对象;
std::unique_lock<std::mutex> myUnique(mutex1);
std::unique_lock<std::mutex> myUnique2(myUnique); //错误,复制mutex对象是非法的
std::unique_lock<std::mutex> myUnique2(mutex1);  //正确,再绑定一个mutex对象是合法的

下面是所有权的传递方法

std::move

std::unique_lock<std::mutex> myUnique(mutex1);
std::unique_lock<std::mutex> myUnique2(std::move(myUnique));  

函数中return一个临时变量

从函数中返回一个局部的unique_lock对象是可以的
返回局部对象会导致系统生成一个临时的unique_lock对象,并调用unique_lock的移动构造函数;

std::unique_lock<std::mutex>rtn_unique_lock()
	{
		std::unique_lock < std::mutex > tmpguard(mutex1);
		return tmpguard;//从函数返回一个局部的unique_lock()对象是可以的,
		//返回这种局部对象tmpguard会导致系统生成临时unique_lock对象,并调用unique_lock的移动构造函数
	}
// ......
std::unique_lock<std::mutex>myUnique2 = rtn_unique_lock();//mutex1的控制权转移给myUnique2
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值