• Mutex和Lock


    =================================版权声明=================================

    版权声明:原创文章 禁止转载 

    请通过右侧公告中的“联系邮箱(wlsandwho@foxmail.com)”联系我

    勿用于学术性引用。

    勿用于商业出版、商业印刷、商业引用以及其他商业用途。                   

    本文不定期修正完善。

    本文链接:https://www.cnblogs.com/wlsandwho/p/13840532.html

    耻辱墙:http://www.cnblogs.com/wlsandwho/p/4206472.html

    =======================================================================

    C++ 异步

    =======================================================================

    mutex

    使用lock锁定,使用unlock解锁。

    使用lock_guard在作用域内自动对mutex加锁和解锁。(基于RAII)

    使用try_lock尝试加锁,成功后需要unlock。

    使用try_lock尝试加锁,成功后使用带adopt_lock的lock_guard接管。

    timed_mutex

    使用try_lock_for尝试在时间段内阻塞等待锁,超时则退出等待。(这个我不感兴趣不写例子了)

    使用try_lock_until尝试在到某时间点之前一直阻塞等待锁,超过该时间点则退出等待。(这个我不感兴趣不写例子了)

    recursive_mutex

    可以多次加锁,当有1次解锁时就释放锁。

    timed_recursive_mutex

    使用try_lock_for尝试在时间段内阻塞等待锁,超时则退出等待。(这个我不感兴趣不写例子了)

    使用try_lock_until尝试在到某时间点之前一直阻塞等待锁,超过该时间点则退出等待。(这个我不感兴趣不写例子了)

    std::lock

    同时锁住多个锁

    std::try_lock

    同事尝试锁住多个锁

    unique_lock

    (这个此处不是重点,应当和Condition Variable配合使用,先不写例子了)

      1 #include <iostream>
      2 #include <future>
      3 #include <functional>
      4 
      5 class CTestA
      6 {
      7 public:
      8     void Do0(std::string& str)
      9     {
     10         for (auto c : str)
     11         {
     12             std::cout.put(c);
     13         }
     14 
     15         std::cout.put('
    ');
     16     }
     17 
     18     void Do1(std::string& str)
     19     {
     20         std::lock_guard<std::mutex> lg(mtx);
     21 
     22         for (auto c:str)
     23         {
     24             std::cout.put(c);
     25         }
     26 
     27         std::cout.put('
    ');
     28     }
     29 
     30 protected:
     31     std::mutex mtx;
     32 };
     33 
     34 void TestA0()
     35 {
     36     //演示,当没有互斥量进行同步时,输出可能会被打乱。
     37 
     38     std::string strHello("This_is_a_lock_guard_demo.");
     39     CTestA oTA;
     40 
     41     //由于是类成员函数调用了复杂的参数(string),所以这里用std::bind作为第二个参数。当然可以用lambda但我不喜欢。
     42     //strHello可能需要std::ref,这里省略了因为不是本节主要内容。
     43     auto fA01 = std::async(std::launch::async, std::bind(&CTestA::Do0, &oTA, strHello));
     44     auto fA02 = std::async(std::launch::async, std::bind(&CTestA::Do0, &oTA, strHello));
     45 
     46     fA01.get();
     47     fA02.get();
     48 }
     49 
     50 void TestA1()
     51 {
     52     //演示,当有互斥量进行同步时,输出正常。
     53 
     54     std::string strHello("This_is_a_lock_guard_demo.");
     55     CTestA oTA;
     56 
     57     auto fA11 = std::async(std::launch::async, std::bind(&CTestA::Do1, &oTA, strHello));
     58     auto fA12 = std::async(std::launch::async, std::bind(&CTestA::Do1, &oTA, strHello));
     59 
     60     fA11.get();
     61     fA12.get();
     62 }
     63 
     64 class CTestB
     65 {
     66 public:
     67     void Do01()
     68     {
     69         std::lock_guard<std::mutex> lg(mtx);
     70         std::cout << "Do01()" << std::endl;
     71     }
     72     
     73     void Do02()
     74     {
     75         std::lock_guard<std::mutex> lg(mtx);
     76 
     77         std::cout << "Do02()...begin" << std::endl;
     78         Do01();
     79         std::cout << "Do02()...end" << std::endl;
     80     }
     81 
     82     void Do11()
     83     {
     84         std::lock_guard<std::recursive_mutex> lg(rmtx);
     85 
     86         std::cout << "Do11()" << std::endl;
     87     }
     88 
     89     void Do12()
     90     {
     91         std::lock_guard<std::recursive_mutex> lg(rmtx);
     92 
     93         std::cout << "Do12()...begin" << std::endl;
     94         Do11();
     95         std::cout << "Do12()...end" << std::endl;
     96     }
     97 
     98 protected:
     99     std::mutex mtx;
    100     std::recursive_mutex rmtx;
    101 };
    102 
    103 void TestB0()
    104 {
    105     CTestB oB0;
    106     oB0.Do02();//未使用递归互斥量时,嵌套调用,引发异常。
    107 }
    108 
    109 void TestB1()
    110 {
    111     CTestB oB0;
    112     oB0.Do12();//使用递归互斥量,嵌套调用,正常运行。
    113     oB0.Do11();//能够够正常运行。
    114 }
    115 
    116 class CTestC
    117 {
    118 public:
    119     void Do01()
    120     {
    121         mtx.lock();
    122         std::cout << "Do01()...lock" << std::endl;
    123     }
    124     void Do02()
    125     {
    126         mtx.unlock();
    127         std::cout << "Do02()...unlock" << std::endl;
    128     }
    129 
    130     void Do11()
    131     {
    132         if (mtx.try_lock())
    133         {
    134             std::cout << "Do11()...try_lock" << std::endl;
    135 
    136             mtx.unlock();
    137             std::cout << "Do11()...unlock" << std::endl;
    138         }
    139         else
    140         {
    141             std::cout << "Do11()...try_lock failed" << std::endl;
    142         }
    143     }
    144     void Do12()
    145     {
    146         if (mtx.try_lock())
    147         {
    148             std::cout << "Do12()...try_lock,use adopt_lock" << std::endl;
    149 
    150             std::lock_guard<std::mutex> lg(mtx, std::adopt_lock);//采用了mtx之前的状态,并在作用域结束后释放mtx
    151         }
    152         else
    153         {
    154             std::cout << "Do12()...try_lock failed" << std::endl;
    155         }
    156     }
    157 protected:
    158     std::mutex mtx;
    159 };
    160 
    161 void TestC1()
    162 {
    163     //此处使用单一线程模拟多线程时交错执行的情形
    164     CTestC oTC;
    165 
    166     //////////////////////////////////////////////////////////////////////////
    167     //失败的情形
    168 
    169     //使用mutex的try_lock功能,并用unlock释放。
    170     oTC.Do01();
    171     oTC.Do11();
    172     oTC.Do02();
    173     std::cout << "-----------" << std::endl;
    174 
    175     //使用mutex的try_lock功能,使用带adopt_lock的lock_guard接管。
    176     oTC.Do01();
    177     oTC.Do12();
    178     oTC.Do02();
    179     std::cout << "-----------" << std::endl;
    180 
    181     //////////////////////////////////////////////////////////////////////////
    182     //成功的情形
    183 
    184     oTC.Do11();//使用mutex的try_lock功能,并用unlock释放。
    185     std::cout << "-----------" << std::endl;
    186 
    187     oTC.Do12();//使用mutex的try_lock功能,使用带adopt_lock的lock_guard接管。
    188     std::cout << "-----------" << std::endl;
    189 }
    190 
    191 class CTestD
    192 {
    193 public:
    194     void Do01()
    195     {
    196         std::lock_guard<std::mutex> lg1(mtx1);
    197         std::cout << "Do01 Get mtx1" << std::endl;
    198         std::this_thread::sleep_for(std::chrono::seconds(1));
    199 
    200         std::lock_guard<std::mutex> lg2(mtx2);
    201         std::cout << "Do01 Get mtx2" << std::endl;
    202         std::this_thread::sleep_for(std::chrono::seconds(2));
    203     }
    204 
    205     void Do02()
    206     {
    207         std::lock_guard<std::mutex> lg2(mtx2);
    208         std::cout << "Do02 Get mtx2" << std::endl;
    209         std::this_thread::sleep_for(std::chrono::seconds(2));
    210 
    211         std::lock_guard<std::mutex> lg1(mtx1);
    212         std::cout << "Do02 Get mtx1" << std::endl;
    213     }
    214 
    215     void Do03()
    216     {
    217         std::lock_guard<std::mutex> lg2(mtx2);
    218         std::cout << "Do03 Get mtx2" << std::endl;
    219         std::this_thread::sleep_for(std::chrono::seconds(5));
    220     }
    221 
    222     void Do11()
    223     {
    224         std::lock(mtx1, mtx2);
    225         std::lock_guard<std::mutex> lg1(mtx1, std::adopt_lock);
    226         std::lock_guard<std::mutex> lg2(mtx2, std::adopt_lock);
    227         std::cout << "Do11 Get mtx1 mtx2" << std::endl;
    228         std::this_thread::sleep_for(std::chrono::seconds(2));
    229 
    230     }
    231 
    232     void Do12()
    233     {
    234         std::lock(mtx2,mtx1);
    235         std::lock_guard<std::mutex> lg2(mtx2, std::adopt_lock);
    236         std::lock_guard<std::mutex> lg1(mtx1, std::adopt_lock);
    237         std::cout << "Do12 Get mtx2 mtx1" << std::endl;
    238         std::this_thread::sleep_for(std::chrono::seconds(2));
    239     }
    240 
    241     void Do21()
    242     {
    243         int idx=std::try_lock(mtx1, mtx2);
    244         if (idx<0)
    245         {
    246             std::lock_guard<std::mutex> lg2(mtx2, std::adopt_lock);
    247             std::lock_guard<std::mutex> lg1(mtx1, std::adopt_lock);
    248             std::cout << "Do21 Get mtx1 mtx2" << std::endl;
    249         }
    250         else
    251         {
    252             std::cout << "Do21 did not get "<<idx+1 << std::endl;
    253         }
    254     }
    255 
    256 protected:
    257     std::mutex mtx1;
    258     std::mutex mtx2;
    259 };
    260 
    261 void TestD01()
    262 {
    263     //Do01与Do02的顺序相反造成死锁
    264     CTestD oTD;
    265     auto f01 = std::async(std::launch::async, &CTestD::Do01, &oTD);
    266     auto f02 = std::async(std::launch::async, &CTestD::Do02, &oTD);
    267     f01.get();
    268     f02.get();
    269 }
    270 
    271 void TestD02()
    272 {
    273     //Do01过了很久才拿到所有的锁
    274     CTestD oTD;
    275     auto f01 = std::async(std::launch::async, &CTestD::Do01, &oTD);
    276     auto f03 = std::async(std::launch::async, &CTestD::Do03, &oTD);
    277     f01.get();
    278     f03.get();
    279 }
    280 
    281 void TestD11()
    282 {
    283     //避免了死锁
    284 
    285     CTestD oTD;
    286     auto f01 = std::async(std::launch::async, &CTestD::Do02, &oTD);
    287     auto f11 = std::async(std::launch::async, &CTestD::Do11, &oTD);
    288     f01.get();
    289     f11.get();
    290 }
    291 
    292 void TestD12()
    293 {
    294     //避免了死锁
    295 
    296     CTestD oTD;
    297     auto f11 = std::async(std::launch::async, &CTestD::Do11, &oTD);
    298     auto f12 = std::async(std::launch::async, &CTestD::Do12, &oTD);
    299     f11.get();
    300     f12.get();
    301 }
    302 
    303 void TestD21()
    304 {
    305     //try_lock
    306 
    307     CTestD oTD;
    308     auto f03 = std::async(std::launch::async, &CTestD::Do03, &oTD);
    309     auto f21 = std::async(std::launch::async, &CTestD::Do21, &oTD);
    310     f03.get();
    311     f21.get();
    312 }
    313 
    314 int main()
    315 {
    316     std::cout << "-----------A0-------------" << std::endl;
    317     TestA0();
    318     std::cout << "-----------A1-------------" << std::endl;
    319     TestA1();
    320 
    321     std::cout << "-----------B0-------------" << std::endl;
    322     //TestB0();//发生异常
    323     std::cout << "-----------B1-------------" << std::endl;
    324     TestB1();
    325 
    326     std::cout << "-----------C1-------------" << std::endl;
    327     TestC1();
    328 
    329     std::cout << "-----------D01-------------" << std::endl;
    330     //TestD01();//死锁
    331     std::cout << "-----------02" << std::endl;
    332     TestD02();
    333     std::cout << "-----------11" << std::endl;
    334     TestD11();
    335     std::cout << "-----------12" << std::endl;
    336     TestD12();
    337     std::cout << "-----------21" << std::endl;
    338     TestD21();
    339 
    340     std::cout << "-----------End-------------" << std::endl;
    341     return 0;
    342 }

    运行结果

  • 相关阅读:
    vue2手写vuex
    200.岛屿数量(DFS M-岛屿系列)
    739.每日温度(栈M)
    150.逆波兰表达式求值(栈M)
    20.有效的括号(栈L)
    前端性能优化与SEO优化整理
    Typescript:类型断言
    如何在浏览器中快速调试Typescript
    Typescript:枚举
    Typescript:接口
  • 原文地址:https://www.cnblogs.com/wlsandwho/p/13840532.html
Copyright © 2020-2023  润新知