《白话C++》第12章并发,Page577 12.5.3 “半自动”锁

全自动固然好,但在一些特定环境下,如果没办法全自动,那也不代表就马上变成“全手动”操作,这中间还有一个很科学的“半自动”过程。

lock_guard <T>是封装互斥量得到一把全自动化的锁,变量定义时自动上锁,变量析构时自动解锁。

到“原子操作”时,就会有该全自动锁无法适用的代码结构。

unique_lock <T> 是标准库提供的“半自动化锁”模板,具备lock_guard <T>的全部功能:

......
__concurrency_mutex_block_begin_
{
    //“_m”是mutex对象
    std::unique_lock <std::mutex> lock(_m);
    ......
}
......

 lock定义时,自动为互斥量“_m”加锁,析构时自动解锁。接下来就是各种半自动功能所要解决的问题了。

问1:

假设手上的互斥量已经加上锁了,但希望通过一个lock对象帮助自动解锁,怎么办?比如有这么一段代码:

std::mutex M;
M.lock(); //种原因,这里M就是自行锁上了

......
if(...)
{
    M.unlock();
    return;
}

try
{
    ......
    M.unlock();
    return;
}
catch(...)
{
    M.unlock();
    return;
}

函数有几个出口,就写了几处的解锁操作,这太讨厌了,此局何解?

答1:

如无必要,显然还是要避免M擅自加锁。不过如果无可避免,那么只能面对现实。此时我们定义一个特殊的unique_lock <T>对象:

std::mutex M;
M.lock();//种种原因,这里M就是自行锁上了

......
std::unique_lock <std::mutex> lock(_m, std::adopt_lock);

......//后面不需要任何手工解锁代码

adopt意为“收养、领养”。用它作第二个入参,构造一把锁,将认定接受的互斥量已经上错,不会再次上锁!

这个功能,std::lock_guard <T>也具备。

问2:

接受一个未上锁的互斥量,但构造时不对它上锁,std::unique_lock能做到吗?又问,std::lock_guard能做到吗?

答2:

std::unique_lock可以做到。第二个入参改为std::defer_lock,则构造时不对互斥量调用lock()操作。这个本事,std::lock_guard不具备。

......
//暂不加锁
std::unique_lock <std::mutex> lock(_m, std::defer_lock);

......
//过一会儿才加锁
lock.lock();
......//后续自动解锁功能依旧

问3:

可不可以完全通过unique_lock <T>实现手工对互斥量加锁、解锁?

答3:

完全可以。前例已有unique_lock<T>对象调用lock()的方法。对用也可以手工调用unlock()方法。unique_lock <T>对象在析构时会自动判断是否还需解锁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值