zoukankan      html  css  js  c++  java
  • 【C++多线程】lock_guard<T>类和unique_lock<T>类

    lock_guard<T>

      使用的RAII机制,互斥量在lock_guard<T>对象构造时lock,在其析构时unlock。主要是为了解决在手动lock和unlock时忘记unlock的情况。lock_guard类不可复制,因为一个对象只能关联一个mutex。

    锁的粒度

      锁的粒度用来描述通过一个锁保护着的数据量大小。一个细粒度锁能够保护较小的数据量,一个粗粒度锁能够保护较多的数据量。选择粒度对于锁来说很重要,为了保护对应的数据,保证锁有能力保护这些数据也很重要。所以一如了更加灵活的unique_lock<T>。

    unique_lock<T>

      unique_lock<T> 是通用互斥包装器,允许延迟锁定、锁定的有时限尝试、递归锁定、所有权转移和与条件变量一同使用unique_lock<T>可移动,不可复制。unique_lock<T>能够在需要是lock,用完后unlock,当生命周期结束时若此时互斥量没有解锁,也会像lock_guard<T>一样析构解锁。也就是说类unique_lock<T>是类lock_guard<T>的一个超集。unique_lock<T>相比lock_guard<T>更加灵活,但是效率差一些,因为占用更多的内存。以下是cppreference.com对unique_lock<T>的说明

     随时unlock和lock

     1 #include <iostream>
     2 #include <thread>
     3 #include <mutex>
     4 #include <list>
     5 using namespace std;
     6 
     7 class A {
     8 public:
     9     void input()
    10     {
    11         for (int i = 0; i < 1000; i++)
    12         {
    13             // lock_guard<mutex> guard(my_mutex);
    14             unique_lock<mutex> my_lock(my_mutex);   //构造时自动lock
    15             ilst.push_back(i);
    16             my_lock.unlock();   //在生命周期结束前提前unlock,为其他线程执行争取时间
    17             cout << "加入数据:" << i << endl;
    18             my_lock.lock();     //在需要时又重新上锁
    19 
    20             //do something with my_mutex
    21 
    22         }  //生命周期结束,自动在析构函数中unlock
    23  
    24     }
    25 
    26     void output()
    27     {
    28         for (int i = 0; i < 1000; i++)
    29         {
    30             // lock_guard<mutex> guard(my_mutex);
    31             unique_lock<mutex> my_lock(my_mutex);
    32             if (!ilst.empty())
    33             {
    34                 cout << "读读读读出数据:" << ilst.front() << endl;
    35                 ilst.pop_front();
    36             }
    37         }
    38     }
    39  
    40 private:
    41      list<int> ilst;
    42      mutex my_mutex;
    43 };
    44  
    45 int  main()
    46 {
    47     A a;
    48     thread t1(&A::input, &a); 
    49     thread t2(&A::output, &a);
    50     t1.join();
    51     t2.join();
    52     return 0;
    53
    }

    所有权转移

      unique_lock<T>类和unique_ptr类一样属于只能移动,不能复制的类型。unique_lock<T>转移所有权的方式有两种:一是使用std::move();二是添加成员函数,返回临时对象。

    #include <iostream>
    #include <thread>
    #include <mutex>
    #include <list>
    using namespace std;
    
    class A {
    public:
        // 添加成员函数转移所有权
        unique_lock<mutex> mymove()
        {
            return unique_lock<mutex>(my_mutex); 
        }
    
        void input()
        {
            for (int i = 0; i < 1000; i++)
            {
                unique_lock<mutex> my_lock = mymove();  //
                ilst.push_back(i);
                cout << "加入数据:" << i << endl;
            } 
     
        }
    
        void output()
        {
            for (int i = 0; i < 1000; i++)
            {
                unique_lock<mutex> my_lock1(my_mutex); //此时my_lock1与my_mutex关联
                unique_lock<mutex> my_lock2(move(my_lock1)); //使用std::move,将my_lock2与my_mutex关联
                if (!ilst.empty())
                {
                    cout << "读读读读出数据:" << ilst.front() << endl;
                    ilst.pop_front();
                }
            }
        }
     
    private:
         list<int> ilst;
         mutex my_mutex;
    };
     
    int  main()
    {
        A a;
        thread t1(&A::input, &a); 
        thread t2(&A::output, &a);
        t1.join();
        t2.join();
        return 0;
    }

    第二参数   

      unique_lock<T> 有几个第二参数,std::adopt_lock,std::try _to_lock,std::defer_lock

      std::adopt_lock,将一个已经上锁的mutex,关联到unique_lock对象,该对象咋构造时不再对mutex上锁。需要程序员自己保证在构造unique_lock对象之前已经上锁。用法示例unique_lock<std::mutex> my_lock(my_mutex, std::adopt_lock)。

      std::try _to_lock,在构造对象时尝试去上锁,如果没有上锁成功,并不阻塞。用法示例unique_lock<std::mutex> my_lock(my_mutex, std::try_to_lock)

      std::defer_lock,在构造对象时,不上锁。所以前提就是之前没有被上锁

     1 #include <iostream>
     2 #include <thread>
     3 #include <mutex>
     4 #include <list>
     5 using namespace std;
     6 
     7 class A {
     8 public:
     9     void input()
    10     {
    11         for (int i = 0; i < 1000; i++)
    12         {
    13             //前提程序员必须先自己上锁
    14             my_mutex.lock();  //前提程序员必须先自己上锁
    15             unique_lock<mutex> my_lock(my_mutex, adopt_lock);   //说明前面已经上锁,构造时不需要再上锁
    16             ilst.push_back(i);
    17             cout << "加入数据:" << i << endl;
    18         }  //生命周期结束,自动在析构函数中unlock
    19  
    20     }
    21 
    22     void output()
    23     {
    24         for (int i = 0; i < 1000; i++)
    25         {
    26             // 前提是前面没有对my_mutex上锁
    27             unique_lock<mutex> my_lock(my_mutex, defer_lock); //初始化一个没有上锁的对象,后面使用是自己上锁
    28             if (!ilst.empty())
    29             {
    30                 cout << "读读读读出数据:" << ilst.front() << endl;
    31                 ilst.pop_front();
    32             }
    33         }
    34     }
    35  
    36 private:
    37      list<int> ilst;
    38      mutex my_mutex;
    39 };
    40  
    41 int  main()
    42 {
    43     A a;
    44     thread t1(&A::input, &a); 
    45     thread t2(&A::output, &a);
    46     t1.join();
    47     t2.join();
    48     return 0;
    49 }
  • 相关阅读:
    angularjs的$on、$emit、$broadcast
    angularjs中的路由介绍详解 ui-route(转)
    ionic入门教程-ionic路由详解(state、route、resolve)(转)
    Cocos Creator 加载使用protobuf第三方库,因为加载顺序报错
    Cocos Creator 计时器错误 cc.Scheduler: Illegal target which doesn't have uuid or instanceId.
    Cocos Creator 构造函数传参警告 Can not instantiate CCClass 'Test' with arguments.
    Cocos Creator 对象池NodePool
    Cocos Creator 坐标系 (convertToWorldSpaceAR、convertToNodeSpaceAR)
    Cocos Creator 常驻节点addPersistRootNode
    Cocos Creator 配合Tiled地图的使用
  • 原文地址:https://www.cnblogs.com/chen-cs/p/13062647.html
Copyright © 2011-2022 走看看