Multi-thread--C++11中std::lock_guard的使用

互斥类的最重要成员函数是lock()和unlock()。在进入临界区时,执行lock()加锁操作,如果这时已经被其它线程锁住,则当前线程在此排队等待。退出临界区时,执行unlock()解锁操作。更好的办法是采用”资源分配时初始化”(RAII)方法来加锁、解锁,这避免了在临界区中因为抛出异常或return等操作导致没有解锁就退出的问题。极大地简化了程序员编写mutex相关的异常处理代码。C++11的标准库中提供了std::lock_guard类模板做mutex的RAII。

std::lock_guard类的构造函数禁用拷贝构造,且禁用移动构造。std::lock_guard类除了构造函数和析构函数外没有其它成员函数

在std::lock_guard对象构造时,传入的mutex对象(即它所管理的mutex对象)会被当前线程锁住。在lock_guard对象被析构时,它所管理的mutex对象会自动解锁,不需要程序员手动调用lock和unlock对mutex进行上锁和解锁操作。lock_guard对象并不负责管理mutex对象的生命周期,lock_guard对象只是简化了mutex对象的上锁和解锁操作,方便线程对互斥量上锁,即在某个lock_guard对象的生命周期内,它所管理的锁对象会一直保持上锁状态;而lock_guard的生命周期结束之后,它所管理的锁对象会被解锁。程序员可以非常方便地使用lock_guard,而不用担心异常安全问题。

std::lock_guard在构造时只被锁定一次,并且在销毁时解锁。

关于std::mutex的基础介绍可以参考: http://blog.csdn.net/fengbingchun/article/details/73521630 

The difference is that you can lock and unlock a std::unique_lock. std::lock_guard will be locked only once on construction and unlocked on destruction.

std::unique_lock has other features that allow it to e.g.: be constructed without locking the mutex immediately but to build the RAII wrapper. However, std::unique_lock might have a tad more overhead(较多开销).

std::lock_guard also provides a convenient RAII wrapper, but cannot lock multiple mutexes safely. It can be used when you need a wrapper for a limited scope, e.g.: a member function.

One of the differences between std::lock_guard and std::unique_lock is that the programmer is able to unlock std::unique_lock, but she/he is not able to unlock std::lock_guard.

下面是从其他文章中copy的测试代码,详细内容介绍可以参考对应的reference:

扫描二维码关注公众号,回复: 5679209 查看本文章

  
  
  1. #include "lock_guard.hpp"
  2. #include <iostream>
  3. #include <thread>
  4. #include <mutex>
  5. #include <stdexcept>
  6. #include <list>
  7. #include <algorithm>
  8. namespace lock_guard_ {
  9. ///////////////////////////////////////////////////////
  10. // reference: http://www.cplusplus.com/reference/mutex/lock_guard/
  11. namespace {
  12. std::mutex mtx;
  13. void print_even(int x) {
  14. if (x % 2 == 0) std:: cout << x << " is even\n";
  15. else throw ( std::logic_error( "not even"));
  16. }
  17. void print_thread_id(int id) {
  18. try {
  19. // using a local lock_guard to lock mtx guarantees unlocking on destruction / exception:
  20. std::lock_guard< std::mutex> lck(mtx);
  21. print_even(id);
  22. } catch ( std::logic_error&) {
  23. std:: cout << "[exception caught]\n";
  24. }
  25. }
  26. }
  27. int test_lock_guard_1()
  28. {
  29. std::thread threads[ 10];
  30. // spawn 10 threads:
  31. for ( int i = 0; i< 10; ++i)
  32. threads[i] = std::thread(print_thread_id, i + 1);
  33. for ( auto& th : threads) th.join();
  34. return 0;
  35. }
  36. ///////////////////////////////////////////////////////////
  37. // reference: http://www.cplusplus.com/reference/mutex/lock_guard/lock_guard/
  38. namespace {
  39. std::mutex mtx2; // mutex for critical section
  40. void print_thread_id2(int id) {
  41. mtx2.lock();
  42. std::lock_guard< std::mutex> lck(mtx2, std::adopt_lock);
  43. std:: cout << "thread #" << id << '\n';
  44. }
  45. }
  46. int test_lock_guard_2()
  47. {
  48. std::thread threads[ 10];
  49. // spawn 10 threads:
  50. for ( int i = 0; i< 10; ++i)
  51. threads[i] = std::thread(print_thread_id2, i + 1);
  52. for ( auto& th : threads) th.join();
  53. return 0;
  54. }
  55. ////////////////////////////////////////////////////////////
  56. // reference: http://en.cppreference.com/w/cpp/thread/lock_guard
  57. namespace {
  58. int g_i = 0;
  59. std::mutex g_i_mutex; // protects g_i
  60. void safe_increment()
  61. {
  62. std::lock_guard< std::mutex> lock(g_i_mutex);
  63. ++g_i;
  64. std:: cout << std::this_thread::get_id() << ": " << g_i << '\n';
  65. // g_i_mutex is automatically released when lock goes out of scope
  66. }
  67. }
  68. int test_lock_guard_3()
  69. {
  70. std:: cout << "main: " << g_i << '\n';
  71. std:: thread t1(safe_increment);
  72. std:: thread t2(safe_increment);
  73. t1.join();
  74. t2.join();
  75. std:: cout << "main: " << g_i << '\n';
  76. return 0;
  77. }
  78. //////////////////////////////////////////////////////////////////////
  79. // reference: http://www.bogotobogo.com/cplusplus/C11/7_C11_Thread_Sharing_Memory.php
  80. namespace {
  81. // a global variable
  82. std:: list< int> myList;
  83. // a global instance of std::mutex to protect global variable
  84. std::mutex myMutex;
  85. void addToList(int max, int interval)
  86. {
  87. // the access to this function is mutually exclusive
  88. std::lock_guard< std::mutex> guard(myMutex);
  89. for ( int i = 0; i < max; i++) {
  90. if ((i % interval) == 0) myList.push_back(i);
  91. }
  92. }
  93. void printList()
  94. {
  95. // the access to this function is mutually exclusive
  96. std::lock_guard< std::mutex> guard(myMutex);
  97. for ( auto itr = myList.begin(), end_itr = myList.end(); itr != end_itr; ++itr) {
  98. std:: cout << *itr << ",";
  99. }
  100. }
  101. }
  102. int test_lock_guard_4()
  103. {
  104. int max = 100;
  105. std:: thread t1(addToList, max, 1);
  106. std:: thread t2(addToList, max, 10);
  107. std:: thread t3(printList);
  108. t1.join();
  109. t2.join();
  110. t3.join();
  111. return 0;
  112. }
  113. } // namespace lock_guard_

GitHubhttps://github.com/fengbingchun/Messy_Test 

转载自:https://blog.csdn.net/fengbingchun/article/details/78649260

猜你喜欢

转载自blog.csdn.net/baidu_38172402/article/details/88803390
今日推荐