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 }
  • 相关阅读:
    Apache Cassandra 4.0新特性介绍
    NoSQLBench压测工具入门教程
    赵洋:深入了解Materialized View
    PHP与ECMAScript_1_变量与常量
    HTTP_5_通信数据转发程序:代理、网关、隧道
    HTTP_4_返回结果的HTTP状态码
    HTTP_3_HTTP报文
    HTTP_2_HTTP协议概要
    HTTP_1_Web及网络基础
    一个完整的产品设计流程——家庭安全管家
  • 原文地址:https://www.cnblogs.com/chen-cs/p/13062647.html
Copyright © 2011-2022 走看看