zoukankan      html  css  js  c++  java
  • C++11多线程编程(三)——lock_guard和unique_lock

    如果熟悉C++多线程的童鞋可能有了解到实现的互斥锁的机制还有这个写法

    lock_guard<mutex> guard(mt);

    那么这句话是什么意思呢?为什么又要搞个这样的写法呢?

    这个也是构造互斥锁的写法,就是会在lock_guard构造函数里加锁,在析构函数里解锁,之所以搞了这个写法,C++委员会的解释是防止使用mutex加锁解锁的时候,忘记解锁unlock了。

    #include <iostream>
    #include <thread>
    #include <string>
    #include <mutex>
    using namespace std;
    
    mutex mt;
    void thread_task()
    {
    for (int i = 0; i < 10; i++)
    {
    lock_guard<mutex> guard(mt);
    cout << "print thread: " << i << endl;
    }
    }
    
    int main()
    {
    thread t(thread_task);
    for (int i = 0; i > -10; i--)
    {
    lock_guard<mutex> guard(mt);
    cout << "print main: " << i << endl;
    }
    t.join();
    return 0;
    }

    这里说析构函数里解锁,那么到底什么时候调用析构函数呢?构造函数加锁我们好理解,写下这个语句的时候调用lock_guard<mutex> guard(mt),那么调用析构函数应该是大括号{}结束的时候,也就是说定义lock_guard的时候调用构造函数加锁,大括号解锁的时候调用析构函数解锁。

    虽然lock_guard挺好用的,但是有个很大的缺陷,在定义lock_guard的地方会调用构造函数加锁,在离开定义域的话lock_guard就会被销毁,调用析构函数解锁。这就产生了一个问题,如果这个定义域范围很大的话,那么锁的粒度就很大,很大程序上会影响效率。

    所以为了解决lock_guard锁的粒度过大的原因,unique_lock就出现了。

    unique_lock<mutex> unique(mt);

    这个会在构造函数加锁,然后可以利用unique.unlock()来解锁,所以当你觉得锁的粒度太多的时候,可以利用这个来解锁,而析构的时候会判断当前锁的状态来决定是否解锁,如果当前状态已经是解锁状态了,那么就不会再次解锁,而如果当前状态是加锁状态,就会自动调用unique.unlock()来解锁。而lock_guard在析构的时候一定会解锁,也没有中途解锁的功能。

    当然,方便肯定是有代价的,unique_lock内部会维护一个锁的状态,所以在效率上肯定会比lock_guard慢。

    所以,以上两种加锁解锁的方法,加上前面文章介绍的mutex方法,具体该使用哪一个,要依照具体的业务需求来决定,当然mt.lock()和mt.unlock()不管是哪种情况,是肯定都可以使用的。

    对我而言,总感觉这个lock_guard有点鸡肋而已,完全可以用mutex来替代,忘记解锁的话一般都可以通过调试发现,而且一般情况下都不会忘记。仅仅只是因为怕忘记解锁这个原因的话,真的感觉有点多此一举,徒增学习成本罢了。

    当然也许C++委员会有他们自己的考虑,对于我们而言,也只能记住就是了。

    更多精彩内容,请关注同名公众:一点月光(alittle-moon)

  • 相关阅读:
    算法:最小公倍数的求解方法
    使用C语言中qsort()函数对浮点型数组无法成功排序的问题
    用两个栈模拟实现一个队列
    单链表反向查找
    单链表逆序
    斐波那契(Fibonacci)数列的几种计算机解法
    最大子列和问题
    Visual Studio个人常用快捷键
    数字根(digital root)
    秦九韶算法(霍纳算法)求解多项式
  • 原文地址:https://www.cnblogs.com/kiwiblog/p/14167898.html
Copyright © 2011-2022 走看看