《白话C++》第7章 Page622 规避死锁 使用守护锁

7.16.3规避死锁:

通过前面的例子可见,互斥体基本都是“lock()”和“unlock()”操作结对出现。如果出现光“上锁”不“解锁”的代码,被锁上的代码块就无法再范文,于是所有前来尝试的线程将死等在加锁处……可怕。

【课堂作业】:感受“死锁”

请找出一个使用mutex的前例,去掉其中“unlock”代码,再编译运行,观察程序运行现象。

 将26行注释掉,线程2得到锁之后,将不再释放,造成死锁,运行效果如下:

除了忘记解锁会造成死锁之外,同一线程对同一个互斥体(在未解锁前)再次加锁,也会造成该线程陷入死锁。主要原因是当前的互斥体,属于“不可重入”的互斥体类型。比如:
 

std::mutex output_mutex; //定义一个全局变量

void foo1()
{
    for(int i = 0; i < 20; ++ i)
    {   /**< 死锁 */
        output_mutex.lock();      //加锁一次
        cout << "a-" << i << endl;
        if(i % 3 == 0)
        {
            cout << "进入if判断" << endl;
            output_mutex.lock();      //加锁二次
            cout << "A" << endl;
            output_mutex.unlock();      //解锁二次
            cout << "if判断完毕" << endl;
        }
        output_mutex.unlock();      //解锁一次
    }
}

int main()
{
    thread trd_1(&foo1); //本次线程构造入参:一个函数地址

    trd_1.join(); //等待trd_1所代表的线程执行完毕

    return 0;
}

运行效果:

 其过程如图7-56所示。

图7-56中,①的线程还没取得锁,②的线程取得第一道锁,但由于第二道锁和第一道锁是同一互斥体对象,因此当第一道锁锁上,第二道也将同时锁上,然后同线程还在前行,一旦它遇到第二道锁,它也一样要开始等待期解锁。可是这把锁就是这个线程锁上的,这个线程陷入等地,那谁来开锁呢?

7.16.4  使用守护锁

守护锁基本款:std::lock_guard<T>,采用模板技术写成,适用多种互斥体;内部运用C++之RAII技术中“栈对象离开代码块时,将自动释放并调用析构”这一规律,精巧地实现互斥体的智能解锁功能。

下面是使用守护锁之前和之后的代码对比(为方便排版,将变量output_mutex改名为m):

beforeafter

for(int i = 0; i < 20; ++i)

{

        m.lock();

        cout << "a - " << i << endl;

        m.unlock();

}

for(int i = 0; i < 20; ++i)

{

        lock_guard <mutex> guard(m);

        cout << "a - " << i << endl;

}

lock_guard<T>是个类模板,其模板类型参数是 互斥体类型。对应地,构造守护对象的入参是互斥体对象。使用守护时,代码中丑陋,易忘,易出错的“lock”和“unlock”都不见了,就只剩下它一个守护栈对象(本例中名为guard)。它在构建时,将自动调用入参m的lock方法,而一旦当前语句块(通常这个语句块也是锁的作用范围)结束时,栈对象将自动被释放并调用析构函数,守护对象便在析构函数中调用互斥体的解锁操作。

【小提示】:RAII是“resource acquisition is initialization”的缩写,译为“资源获取即初始化”

  • 12
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值