2025年c++11条件变量虚假唤醒(c++条件变量使用)

c++11条件变量虚假唤醒(c++条件变量使用)p strong 线程 strong p 类 std thread 代表一个可执行线程 使用时必须包含头文件 lt thread gt std thread 可以和普通函数 匿名函数和仿函数 一个实现了 operator 函数的类 一同使用 另外 它允许向线程函数传递任意数量的参数 include amp

大家好,我是讯享网,很高兴认识大家。



 <p><strong>线程</strong></p> 

讯享网

类std::thread代表一个可执行线程,使用时必须包含头文件&lt;thread&gt;。std::thread可以和普通函数,匿名函数和仿函数(一个实现了operator()函数的类)一同使用。另外,它允许向线程函数传递任意数量的参数。

讯享网

  1. #include&nbsp;&lt;thread&gt;&nbsp;
  2. &nbsp;&nbsp;
  3. void&nbsp;func()&nbsp;
  4. {&nbsp;
  5. &nbsp;&nbsp;&nbsp;//&nbsp;do&nbsp;some&nbsp;work&nbsp;
  6. }&nbsp;
  7. &nbsp;&nbsp;
  8. int&nbsp;main()&nbsp;
  9. {&nbsp;
  10. &nbsp;&nbsp;&nbsp;std::thread&nbsp;t(func);&nbsp;
  11. &nbsp;&nbsp;&nbsp;t.join();&nbsp;
  12. &nbsp;&nbsp;
  13. &nbsp;&nbsp;&nbsp;return&nbsp;0;&nbsp;
  14. }&nbsp;
  15. 上例中,t 是一个线程对象,函数func()运行于该线程中。对join()函数的调用将使调用线程(本例是指主线程)一直处于阻塞状态,直到正在执行的线程t执行结束。如果线程函数返回某个值,该值也将被忽略。不过,该函数可以接收任意数量的参数。

    1. void&nbsp;func(int&nbsp;i,&nbsp;double&nbsp;d,&nbsp;const&nbsp;std::string&&nbsp;s)&nbsp;
    2. {&nbsp;
    3. &nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;&lt;&lt;&nbsp;i&nbsp;&lt;&lt;&nbsp;”,&nbsp;“&nbsp;&lt;&lt;&nbsp;d&nbsp;&lt;&lt;&nbsp;”,&nbsp;“&nbsp;&lt;&lt;&nbsp;s&nbsp;&lt;&lt;&nbsp;std::endl;&nbsp;
    4. }&nbsp;
    5. &nbsp;&nbsp;
    6. int&nbsp;main()&nbsp;
    7. {&nbsp;
    8. &nbsp;&nbsp;&nbsp;std::thread&nbsp;t(func,&nbsp;1,&nbsp;12.50,&nbsp;“sample”);&nbsp;
    9. &nbsp;&nbsp;&nbsp;t.join();&nbsp;
    10. &nbsp;&nbsp;
    11. &nbsp;&nbsp;&nbsp;return&nbsp;0;&nbsp;
    12. }&nbsp;
    13. 尽管可以向线程函数传递任意数量的参数,但是所有的参数应当按值传递。如果需要将参数按引用传递,那要向下例所示那样,必须将参数用std::ref 或者std::cref进行封装。

      讯享网

      1. void&nbsp;func(int&&nbsp;a)&nbsp;
      2. {&nbsp;
      3. &nbsp;&nbsp;&nbsp;a++;&nbsp;
      4. }&nbsp;
      5. &nbsp;&nbsp;
      6. int&nbsp;main()&nbsp;
      7. {&nbsp;
      8. &nbsp;&nbsp;&nbsp;int&nbsp;a&nbsp;=&nbsp;42;&nbsp;
      9. &nbsp;&nbsp;&nbsp;std::thread&nbsp;t(func,&nbsp;std::ref(a));&nbsp;
      10. &nbsp;&nbsp;&nbsp;t.join();&nbsp;
      11. &nbsp;&nbsp;
      12. &nbsp;&nbsp;&nbsp;std::cout&nbsp;&lt;&lt;&nbsp;a&nbsp;&lt;&lt;&nbsp;std::endl;&nbsp;
      13. &nbsp;&nbsp;
      14. &nbsp;&nbsp;&nbsp;return&nbsp;0;&nbsp;
      15. }&nbsp;
      16. 该程序打印结果为43,但是如果不用std::ref把参数a进行封装的话,输出结果将为42.

        除了join方法外,该线程类还提供了另外两个方法:

        swap:交换两个线程对象的底层句柄。

        Detach: 允许执行该方法的线程脱离其线程对象而继续独立执行。脱离后的线程不再是可结合线程(你不能等待它们执行结束)。

        1. int&nbsp;main()&nbsp;
        2. {&nbsp;
        3. &nbsp;&nbsp;&nbsp;&nbsp;std::thread&nbsp;t(funct);&nbsp;
        4. &nbsp;&nbsp;&nbsp;&nbsp;t.detach();&nbsp;
        5. &nbsp;&nbsp;
        6. &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;&nbsp;
        7. }&nbsp;
        8. 有一点非常重要,如果线程函数抛出异常,使用常规的try-catch语句是捕获不到该异常的。换句话说,以下的做法是不可行的:

          讯享网

          1. try&nbsp;
          2. {&nbsp;
          3. &nbsp;&nbsp;&nbsp;&nbsp;std::thread&nbsp;t1(func);&nbsp;
          4. &nbsp;&nbsp;&nbsp;&nbsp;std::thread&nbsp;t2(func);&nbsp;
          5. &nbsp;&nbsp;
          6. &nbsp;&nbsp;&nbsp;&nbsp;t1.join();&nbsp;
          7. &nbsp;&nbsp;&nbsp;&nbsp;t2.join();&nbsp;
          8. }&nbsp;
          9. catch(const&nbsp;std::exception&&nbsp;ex)&nbsp;
          10. {&nbsp;
          11. &nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;&lt;&lt;&nbsp;ex.what()&nbsp;&lt;&lt;&nbsp;std::endl;&nbsp;
          12. }&nbsp;
          13. 要在线程间传递异常,你需要在线程函数中捕获他们,将其存储在合适的地方,比便于另外的线程可以随后获取到这些异常。

            1. std::mutex&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_mutex;&nbsp;
            2. std::vector&lt;std::exception_ptr&gt;&nbsp;&nbsp;g_exceptions;&nbsp;
            3. &nbsp;&nbsp;
            4. void&nbsp;throw_function()&nbsp;
            5. {&nbsp;
            6. &nbsp;&nbsp;&nbsp;throw&nbsp;std::exception(“something&nbsp;wrong&nbsp;happened”);&nbsp;
            7. }&nbsp;
            8. &nbsp;&nbsp;
            9. void&nbsp;func()&nbsp;
            10. {&nbsp;
            11. &nbsp;&nbsp;&nbsp;try&nbsp;
            12. &nbsp;&nbsp;&nbsp;{&nbsp;
            13. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw_function();&nbsp;
            14. &nbsp;&nbsp;&nbsp;}&nbsp;
            15. &nbsp;&nbsp;&nbsp;catch(…)&nbsp;
            16. &nbsp;&nbsp;&nbsp;{&nbsp;
            17. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::lock_guard&lt;std::mutex&gt;&nbsp;lock(g_mutex);&nbsp;
            18. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_exceptions.push_back(std::current_exception());&nbsp;
            19. &nbsp;&nbsp;&nbsp;}&nbsp;
            20. }&nbsp;
            21. &nbsp;&nbsp;
            22. int&nbsp;main()&nbsp;
            23. {&nbsp;
            24. &nbsp;&nbsp;&nbsp;g_exceptions.clear();&nbsp;
            25. &nbsp;&nbsp;
            26. &nbsp;&nbsp;&nbsp;std::thread&nbsp;t(func);&nbsp;
            27. &nbsp;&nbsp;&nbsp;t.join();&nbsp;
            28. &nbsp;&nbsp;
            29. &nbsp;&nbsp;&nbsp;for(auto&&nbsp;e&nbsp;:&nbsp;g_exceptions)&nbsp;
            30. &nbsp;&nbsp;&nbsp;{&nbsp;
            31. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;
            32. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
            33. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(e&nbsp;!=&nbsp;nullptr)&nbsp;
            34. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
            35. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::rethrow_exception(e);&nbsp;
            36. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
            37. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
            38. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;catch(const&nbsp;std::exception&&nbsp;e)&nbsp;
            39. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
            40. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;&lt;&lt;&nbsp;e.what()&nbsp;&lt;&lt;&nbsp;std::endl;&nbsp;
            41. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
            42. &nbsp;&nbsp;&nbsp;}&nbsp;
            43. &nbsp;&nbsp;
            44. &nbsp;&nbsp;&nbsp;return&nbsp;0;&nbsp;
            45. }&nbsp;
            46. 想要知道更多的关于捕获和传递异常的知识,可以阅读这两本书在主线程中处理辅助线程抛出的C++异常怎样在线程间传递异常

              在深入学习之前,有一点需要注意 &lt;thread&gt;头文件在命名空间std::this_thread中提供了一些帮助函数:

              • get_id: 返回当前线程的id.
              • yield:在处于等待状态时,可以让调度器先运行其他可用的线程。
              • sleep_for:阻塞当前线程,时间不少于其参数指定的时间。
              • sleep_util:在参数指定的时间到达之前,使当前线程一直处于阻塞状态。

              #p#

              在上面的例子中,我需要对vector g_exceptions进行同步访问,以确保在同一时间只能有一个线程向其中添加新元素。为此,我使用了互斥量,并对该互斥进行加锁。互斥量是一个核心 同步原语,C++ 11的&lt;mutex&gt;头文件里包含了四种不同的互斥量。

              • Mutex: 提供了核心函数 lock() 和 unlock(),以及非阻塞方法的try_lock()方法,一旦互斥量不可用,该方法会立即返回。
              • Recursive_mutex:允许在同一个线程中对一个互斥量的多次请求。
              • Timed_mutex:同上面的mutex类似,但它还有另外两个方法 try_lock_for() 和 try_lock_until(),分别用于在某个时间段里或者某个时刻到达之间获取该互斥量。
              • Recursive_timed_mutex: 结合了timed_mutex 和recuseive_mutex的使用。

              下面是一个使用了std::mutex的例子(注意前面提到过的帮助函数get_id()和sleep_for()的用法)。

              讯享网

              1. #include&nbsp;&lt;iostream&gt;&nbsp;
              2. #include&nbsp;&lt;thread&gt;&nbsp;
              3. #include&nbsp;&lt;mutex&gt;&nbsp;
              4. #include&nbsp;&lt;chrono&gt;&nbsp;
              5. &nbsp;&nbsp;
              6. std::mutex&nbsp;g_lock;&nbsp;
              7. &nbsp;&nbsp;
              8. void&nbsp;func()&nbsp;
              9. {&nbsp;
              10. &nbsp;&nbsp;&nbsp;&nbsp;g_lock.lock();&nbsp;
              11. &nbsp;&nbsp;
              12. &nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;&lt;&lt;&nbsp;“entered&nbsp;thread&nbsp;”&nbsp;&lt;&lt;&nbsp;std::this_thread::get_id()&nbsp;&lt;&lt;&nbsp;std::endl;&nbsp;
              13. &nbsp;&nbsp;&nbsp;&nbsp;std::this_thread::sleep_for(std::chrono::seconds(rand()&nbsp;%&nbsp;10));&nbsp;
              14. &nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;&lt;&lt;&nbsp;“leaving&nbsp;thread&nbsp;”&nbsp;&lt;&lt;&nbsp;std::this_thread::get_id()&nbsp;&lt;&lt;&nbsp;std::endl;&nbsp;
              15. &nbsp;&nbsp;
              16. &nbsp;&nbsp;&nbsp;&nbsp;g_lock.unlock();&nbsp;
              17. }&nbsp;
              18. &nbsp;&nbsp;
              19. int&nbsp;main()&nbsp;
              20. {&nbsp;
              21. &nbsp;&nbsp;&nbsp;&nbsp;srand((unsigned&nbsp;int)time(0));&nbsp;
              22. &nbsp;&nbsp;
              23. &nbsp;&nbsp;&nbsp;&nbsp;std::thread&nbsp;t1(func);&nbsp;
              24. &nbsp;&nbsp;&nbsp;&nbsp;std::thread&nbsp;t2(func);&nbsp;
              25. &nbsp;&nbsp;&nbsp;&nbsp;std::thread&nbsp;t3(func);&nbsp;
              26. &nbsp;&nbsp;
              27. &nbsp;&nbsp;&nbsp;&nbsp;t1.join();&nbsp;
              28. &nbsp;&nbsp;&nbsp;&nbsp;t2.join();&nbsp;
              29. &nbsp;&nbsp;&nbsp;&nbsp;t3.join();&nbsp;
              30. &nbsp;&nbsp;
              31. &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;&nbsp;
              32. }&nbsp;
              33. 输出结果如下所示:

                1. entered&nbsp;thread&nbsp;10144&nbsp;
                2. leaving&nbsp;thread&nbsp;10144&nbsp;
                3. entered&nbsp;thread&nbsp;4188&nbsp;
                4. leaving&nbsp;thread&nbsp;4188&nbsp;
                5. entered&nbsp;thread&nbsp;3424&nbsp;
                6. leaving&nbsp;thread&nbsp;3424&nbsp;
                7. lock()和unlock()这两个方法应该一目了然,*个方法用来对互斥量加锁,如果互斥量不可用,便处于阻塞状态。后者则用来对互斥量解锁。

                  下面这个例子展示了一个简单的线程安全容器(内部使用std::vector).这个容器带有添加单个元素的add()方法和添加多个元素的addrange()方法,addrange()方法内部仅仅调用了add()方法。

                  注意:就像下面的评论里所指出的一样,由于某些原因,包括使用了va_args,这不是一个标准的线程安全容器。而且,dump()方法也不是容器 的方法,从真正的实现上来说,它只是一个帮助(独立的)函数。这个例子仅仅用来告诉大家一些有关互斥量的概念,而不是实现一个完全成熟的,无任何错误的线 程安全容器。

                  讯享网

                  1. template&nbsp;&lt;typename&nbsp;T&gt;&nbsp;
                  2. class&nbsp;container&nbsp;
                  3. {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
                  4. &nbsp;&nbsp;&nbsp;&nbsp;std::mutex&nbsp;_lock;&nbsp;
                  5. &nbsp;&nbsp;&nbsp;&nbsp;std::vector&lt;T&gt;&nbsp;_elements;&nbsp;
                  6. public:&nbsp;
                  7. &nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;add(T&nbsp;element)&nbsp;
                  8. &nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
                  9. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_lock.lock();&nbsp;
                  10. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_elements.push_back(element);&nbsp;
                  11. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_lock.unlock();&nbsp;
                  12. &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
                  13. &nbsp;&nbsp;
                  14. &nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;addrange(int&nbsp;num,&nbsp;…)&nbsp;
                  15. &nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
                  16. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;va_list&nbsp;arguments;&nbsp;
                  17. &nbsp;&nbsp;
                  18. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;va_start(arguments,&nbsp;num);&nbsp;
                  19. &nbsp;&nbsp;
                  20. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;num;&nbsp;i++)&nbsp;
                  21. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
                  22. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_lock.lock();&nbsp;
                  23. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;add(va_arg(arguments,&nbsp;T));&nbsp;
                  24. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_lock.unlock();&nbsp;
                  25. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
                  26. &nbsp;&nbsp;
                  27. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;va_end(arguments);&nbsp;
                  28. &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
                  29. &nbsp;&nbsp;
                  30. &nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;dump()&nbsp;
                  31. &nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
                  32. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_lock.lock();&nbsp;
                  33. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(auto&nbsp;e&nbsp;:&nbsp;_elements)&nbsp;
                  34. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;&lt;&lt;&nbsp;e&nbsp;&lt;&lt;&nbsp;std::endl;&nbsp;
                  35. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_lock.unlock();&nbsp;
                  36. &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
                  37. };&nbsp;
                  38. &nbsp;&nbsp;
                  39. void&nbsp;func(container&lt;int&gt;&&nbsp;cont)&nbsp;
                  40. {&nbsp;
                  41. &nbsp;&nbsp;&nbsp;&nbsp;cont.addrange(3,&nbsp;rand(),&nbsp;rand(),&nbsp;rand());&nbsp;
                  42. }&nbsp;
                  43. &nbsp;&nbsp;
                  44. int&nbsp;main()&nbsp;
                  45. {&nbsp;
                  46. &nbsp;&nbsp;&nbsp;&nbsp;srand((unsigned&nbsp;int)time(0));&nbsp;
                  47. &nbsp;&nbsp;
                  48. &nbsp;&nbsp;&nbsp;&nbsp;container&lt;int&gt;&nbsp;cont;&nbsp;
                  49. &nbsp;&nbsp;
                  50. &nbsp;&nbsp;&nbsp;&nbsp;std::thread&nbsp;t1(func,&nbsp;std::ref(cont));&nbsp;
                  51. &nbsp;&nbsp;&nbsp;&nbsp;std::thread&nbsp;t2(func,&nbsp;std::ref(cont));&nbsp;
                  52. &nbsp;&nbsp;&nbsp;&nbsp;std::thread&nbsp;t3(func,&nbsp;std::ref(cont));&nbsp;
                  53. &nbsp;&nbsp;
                  54. &nbsp;&nbsp;&nbsp;&nbsp;t1.join();&nbsp;
                  55. &nbsp;&nbsp;&nbsp;&nbsp;t2.join();&nbsp;
                  56. &nbsp;&nbsp;&nbsp;&nbsp;t3.join();&nbsp;
                  57. &nbsp;&nbsp;
                  58. &nbsp;&nbsp;&nbsp;&nbsp;cont.dump();&nbsp;
                  59. &nbsp;&nbsp;
                  60. &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;&nbsp;
                  61. }&nbsp;
                  62. 运行该程序时,会进入死锁状态。原因是该容器试图多次去获取同一个互斥量,却一直没有释放它,这样是不可行的。


                    讯享网

                    在这里,使用std::recursive_mutex就可以很好地解决这个问题,它允许同一个线程多次获取同一个互斥量,可获取的互斥量的次数并没有具体说明。但是一旦超过次数,再对lock进行调用就会抛出std::system_error错误异常。

                    #p#

                    要想修改上述代码中的问题(除了修改addrange()方法的实现,使它不去调用lock()和unlock()),还可以将互斥量std::mutex改为std::recursive_mutex

                    1. template&nbsp;&lt;typename&nbsp;T&gt;&nbsp;
                    2. class&nbsp;container&nbsp;
                    3. {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
                    4. &nbsp;&nbsp;&nbsp;&nbsp;std::mutex&nbsp;_lock;&nbsp;
                    5. &nbsp;&nbsp;&nbsp;&nbsp;std::vector&lt;T&gt;&nbsp;_elements;&nbsp;
                    6. public:&nbsp;
                    7. &nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;add(T&nbsp;element)&nbsp;
                    8. &nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
                    9. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_lock.lock();&nbsp;
                    10. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_elements.push_back(element);&nbsp;
                    11. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_lock.unlock();&nbsp;
                    12. &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
                    13. &nbsp;&nbsp;
                    14. &nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;addrange(int&nbsp;num,&nbsp;…)&nbsp;
                    15. &nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
                    16. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;va_list&nbsp;arguments;&nbsp;
                    17. &nbsp;&nbsp;
                    18. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;va_start(arguments,&nbsp;num);&nbsp;
                    19. &nbsp;&nbsp;
                    20. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;num;&nbsp;i++)&nbsp;
                    21. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
                    22. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_lock.lock();&nbsp;
                    23. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;add(va_arg(arguments,&nbsp;T));&nbsp;
                    24. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_lock.unlock();&nbsp;
                    25. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
                    26. &nbsp;&nbsp;
                    27. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;va_end(arguments);&nbsp;
                    28. &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
                    29. &nbsp;&nbsp;
                    30. &nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;dump()&nbsp;
                    31. &nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
                    32. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_lock.lock();&nbsp;
                    33. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(auto&nbsp;e&nbsp;:&nbsp;_elements)&nbsp;
                    34. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;&lt;&lt;&nbsp;e&nbsp;&lt;&lt;&nbsp;std::endl;&nbsp;
                    35. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_lock.unlock();&nbsp;
                    36. &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
                    37. };&nbsp;
                    38. &nbsp;&nbsp;
                    39. void&nbsp;func(container&lt;int&gt;&&nbsp;cont)&nbsp;
                    40. {&nbsp;
                    41. &nbsp;&nbsp;&nbsp;&nbsp;cont.addrange(3,&nbsp;rand(),&nbsp;rand(),&nbsp;rand());&nbsp;
                    42. }&nbsp;
                    43. &nbsp;&nbsp;
                    44. int&nbsp;main()&nbsp;
                    45. {&nbsp;
                    46. &nbsp;&nbsp;&nbsp;&nbsp;srand((unsigned&nbsp;int)time(0));&nbsp;
                    47. &nbsp;&nbsp;
                    48. &nbsp;&nbsp;&nbsp;&nbsp;container&lt;int&gt;&nbsp;cont;&nbsp;
                    49. &nbsp;&nbsp;
                    50. &nbsp;&nbsp;&nbsp;&nbsp;std::thread&nbsp;t1(func,&nbsp;std::ref(cont));&nbsp;
                    51. &nbsp;&nbsp;&nbsp;&nbsp;std::thread&nbsp;t2(func,&nbsp;std::ref(cont));&nbsp;
                    52. &nbsp;&nbsp;&nbsp;&nbsp;std::thread&nbsp;t3(func,&nbsp;std::ref(cont));&nbsp;
                    53. &nbsp;&nbsp;
                    54. &nbsp;&nbsp;&nbsp;&nbsp;t1.join();&nbsp;
                    55. &nbsp;&nbsp;&nbsp;&nbsp;t2.join();&nbsp;
                    56. &nbsp;&nbsp;&nbsp;&nbsp;t3.join();&nbsp;
                    57. &nbsp;&nbsp;
                    58. &nbsp;&nbsp;&nbsp;&nbsp;cont.dump();&nbsp;
                    59. &nbsp;&nbsp;
                    60. &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;&nbsp;
                    61. }&nbsp;
                    62. 修改后,就会得到下面的输出结果。

                      讯享网

                      1. 6334&nbsp;
                      2. 18467&nbsp;
                      3. 41&nbsp;
                      4. 6334&nbsp;
                      5. 18467&nbsp;
                      6. 41&nbsp;
                      7. 6334&nbsp;
                      8. 18467&nbsp;
                      9. 41&nbsp;
                      10. 聪明的读者会注意到每次调用func()都会产生相同的数字序列。这是因为种子数是线程本地化的,仅仅在主线程中调用了srand()对种子进行了初始化,在其他工作线程中并没用进行初始化,所以每次都得到相同的数字序列。

                        显式的加锁和解锁会导致一些问题,比如忘记解锁或者请求加锁的顺序不正确,进而产生死锁。该标准提供了一些类和函数帮助解决此类问题。这些封装类保证了在RAII风格上互斥量使用的一致性,可以在给定的代码范围内自动加锁和解锁。封装类包括:

                        Lock_guard:在构造对象时,它试图去获取互斥量的所有权(通过调用lock()),在析构对象时,自动释放互斥量(通过调用unlock()).这是一个的类。

                        Unique_lock:这个一通用的互斥量封装类,不同于lock_guard,它还支持延迟加锁,时间加锁和递归加锁以及锁所有权的转移和条件变量的使用。这也是一个的类,但它是可移动类。

                        有了这些封装类,我们可以像下面这样改写容器类:

                        1. template&nbsp;&lt;typename&nbsp;T&gt;&nbsp;
                        2. class&nbsp;container&nbsp;
                        3. {&nbsp;
                        4. &nbsp;&nbsp;&nbsp;&nbsp;std::recursive_mutex&nbsp;_lock;&nbsp;
                        5. &nbsp;&nbsp;&nbsp;&nbsp;std::vector&lt;T&gt;&nbsp;_elements;&nbsp;
                        6. public:&nbsp;
                        7. &nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;add(T&nbsp;element)&nbsp;
                        8. &nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
                        9. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::lock_guard&lt;std::recursive_mutex&gt;&nbsp;locker(_lock);&nbsp;
                        10. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_elements.push_back(element);&nbsp;
                        11. &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
                        12. &nbsp;&nbsp;
                        13. &nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;addrange(int&nbsp;num,&nbsp;…)&nbsp;
                        14. &nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
                        15. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;va_list&nbsp;arguments;&nbsp;
                        16. &nbsp;&nbsp;
                        17. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;va_start(arguments,&nbsp;num);&nbsp;
                        18. &nbsp;&nbsp;
                        19. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;num;&nbsp;i++)&nbsp;
                        20. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
                        21. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::lock_guard&lt;std::recursive_mutex&gt;&nbsp;locker(_lock);&nbsp;
                        22. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;add(va_arg(arguments,&nbsp;T));&nbsp;
                        23. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
                        24. &nbsp;&nbsp;
                        25. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;va_end(arguments);&nbsp;
                        26. &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
                        27. &nbsp;&nbsp;
                        28. &nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;dump()&nbsp;
                        29. &nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
                        30. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::lock_guard&lt;std::recursive_mutex&gt;&nbsp;locker(_lock);&nbsp;
                        31. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(auto&nbsp;e&nbsp;:&nbsp;_elements)&nbsp;
                        32. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;&lt;&lt;&nbsp;e&nbsp;&lt;&lt;&nbsp;std::endl;&nbsp;
                        33. &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
                        34. };&nbsp;
                        35. #p#

                          有人也许会问,既然dump()方法并没有对容器的状态做任何修改,是不是应该定义为const方法呢?但是你如果将它定义为const,编译器会报出下面的错误:

                          ‘std::lock_guard&lt;_Mutex&gt;::lock_guard(_Mutex &)’ : cannot convert parameter 1 from ‘const std::recursive_mutex’ to ‘std::recursive_mutex &’

                          一个互斥量(不管使用的哪一种实现)必须要获取和释放,这就意味着要调用非const的lock()和unlock()方法。所以从逻辑上来 讲,lock_guard的参数不能使const(因为如果该方法为const,互斥量也必需是const).解决这个问题的办法就是将互斥量定义为可变 的mutable,Mutable允许在常函数中修改状态。

                          不过,这种方法只能用于隐藏或者元状态(就像对计算结果或查询的数据进行缓存,以便下次调用时可以直接使用,不需要进行多次计算和查询。再或者,对在一个对象的实际状态起辅助作用的互斥量进行位的修改)。

                          讯享网

                          1. template&nbsp;&lt;typename&nbsp;T&gt;&nbsp;
                          2. class&nbsp;container&nbsp;
                          3. {&nbsp;
                          4. &nbsp;&nbsp;&nbsp;mutable&nbsp;std::recursive_mutex&nbsp;_lock;&nbsp;
                          5. &nbsp;&nbsp;&nbsp;std::vector&lt;T&gt;&nbsp;_elements;&nbsp;
                          6. public:&nbsp;
                          7. &nbsp;&nbsp;&nbsp;void&nbsp;dump()&nbsp;const&nbsp;
                          8. &nbsp;&nbsp;&nbsp;{&nbsp;
                          9. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::lock_guard&lt;std::recursive_mutex&gt;&nbsp;locker(_lock);&nbsp;
                          10. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(auto&nbsp;e&nbsp;:&nbsp;_elements)&nbsp;
                          11. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;&lt;&lt;&nbsp;e&nbsp;&lt;&lt;&nbsp;std::endl;&nbsp;
                          12. &nbsp;&nbsp;&nbsp;}&nbsp;
                          13. };&nbsp;
                          14. 这些封装类的构造函数可以重载,接受一个参数用来指明加锁策略。可用的策略如下:

                            • defer_lock of type defer_lock_t:不获取互斥量的拥有权
                            • try_to_lock of type try_to_lock_t:在不阻塞的情况下试图获取互斥量的拥有权
                            • adopte_lock of type adopt_lock_t:假设调用线程已经拥有互斥量的所有权&nbsp;

                            这些策略的声明如下:

                            1. struct&nbsp;defer_lock_t&nbsp;{&nbsp;};&nbsp;
                            2. struct&nbsp;try_to_lock_t&nbsp;{&nbsp;};&nbsp;
                            3. struct&nbsp;adopt_lock_t&nbsp;{&nbsp;};&nbsp;
                            4. &nbsp;&nbsp;
                            5. constexpr&nbsp;std::defer_lock_t&nbsp;defer_lock&nbsp;=&nbsp;std::defer_lock_t();&nbsp;
                            6. constexpr&nbsp;std::try_to_lock_t&nbsp;try_to_lock&nbsp;=&nbsp;std::try_to_lock_t();&nbsp;
                            7. constexpr&nbsp;std::adopt_lock_t&nbsp;adopt_lock&nbsp;=&nbsp;std::adopt_lock_t();&nbsp;
                            8. 除了这些互斥量的封装类,该标准还提供了两个方法,用于对一个或多个互斥量进行加锁。

                              • lock:使用一种可以避免死锁的算法对互斥量加锁(通过调用lock(),try_lock()和unlock()).
                              • try_lock():按照互斥量被指定的顺序,试着通过调用try_lock()来对多个互斥量加锁。

                              这是一个发生死锁的例子:有一个用来存储元素的容器和一个函数exchange(),该函数用来交换两个容器中的元素。要成为线程安全函数,该函数通过获取每个容器的互斥量,来对两个容器的访问进行同步操作。

                              讯享网

                              1. template&nbsp;&lt;typename&nbsp;T&gt;&nbsp;
                              2. class&nbsp;container&nbsp;
                              3. {&nbsp;
                              4. public:&nbsp;
                              5. &nbsp;&nbsp;&nbsp;&nbsp;std::mutex&nbsp;_lock;&nbsp;
                              6. &nbsp;&nbsp;&nbsp;&nbsp;std::set&lt;T&gt;&nbsp;_elements;&nbsp;
                              7. &nbsp;&nbsp;
                              8. &nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;add(T&nbsp;element)&nbsp;
                              9. &nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
                              10. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_elements.insert(element);&nbsp;
                              11. &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
                              12. &nbsp;&nbsp;
                              13. &nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;remove(T&nbsp;element)&nbsp;
                              14. &nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
                              15. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_elements.erase(element);&nbsp;
                              16. &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
                              17. };&nbsp;
                              18. &nbsp;&nbsp;
                              19. void&nbsp;exchange(container&lt;int&gt;&&nbsp;cont1,&nbsp;container&lt;int&gt;&&nbsp;cont2,&nbsp;int&nbsp;value)&nbsp;
                              20. {&nbsp;
                              21. &nbsp;&nbsp;&nbsp;&nbsp;cont1._lock.lock();&nbsp;
                              22. &nbsp;&nbsp;&nbsp;&nbsp;std::this_thread::sleep_for(std::chrono::seconds(1));&nbsp;//&nbsp;&lt;–&nbsp;forces&nbsp;context&nbsp;switch&nbsp;to&nbsp;simulate&nbsp;the&nbsp;deadlock&nbsp;
                              23. &nbsp;&nbsp;&nbsp;&nbsp;cont2._lock.lock();&nbsp;&nbsp;&nbsp;&nbsp;
                              24. &nbsp;&nbsp;
                              25. &nbsp;&nbsp;&nbsp;&nbsp;cont1.remove(value);&nbsp;
                              26. &nbsp;&nbsp;&nbsp;&nbsp;cont2.add(value);&nbsp;
                              27. &nbsp;&nbsp;
                              28. &nbsp;&nbsp;&nbsp;&nbsp;cont1._lock.unlock();&nbsp;
                              29. &nbsp;&nbsp;&nbsp;&nbsp;cont2._lock.unlock();&nbsp;
                              30. }&nbsp;
                              31. 假设这个函数是由两个不同的线程进行调用的,个线程中,一个元素从容器1中移除,添加到容器2中。第二个线程中,该元素又从容器2移除添加到容器1中。这种做法会导致发生死锁(如果在获取个锁后,线程上下文刚好从一个线程切换到另一个线程,导致发生死锁)。

                                1. int&nbsp;main()&nbsp;
                                2. {&nbsp;
                                3. &nbsp;&nbsp;&nbsp;&nbsp;srand((unsigned&nbsp;int)time(NULL));&nbsp;
                                4. &nbsp;&nbsp;
                                5. &nbsp;&nbsp;&nbsp;&nbsp;container&lt;int&gt;&nbsp;cont1;&nbsp;
                                6. &nbsp;&nbsp;&nbsp;&nbsp;cont1.add(1);&nbsp;
                                7. &nbsp;&nbsp;&nbsp;&nbsp;cont1.add(2);&nbsp;
                                8. &nbsp;&nbsp;&nbsp;&nbsp;cont1.add(3);&nbsp;
                                9. &nbsp;&nbsp;
                                10. &nbsp;&nbsp;&nbsp;&nbsp;container&lt;int&gt;&nbsp;cont2;&nbsp;
                                11. &nbsp;&nbsp;&nbsp;&nbsp;cont2.add(4);&nbsp;
                                12. &nbsp;&nbsp;&nbsp;&nbsp;cont2.add(5);&nbsp;
                                13. &nbsp;&nbsp;&nbsp;&nbsp;cont2.add(6);&nbsp;
                                14. &nbsp;&nbsp;
                                15. &nbsp;&nbsp;&nbsp;&nbsp;std::thread&nbsp;t1(exchange,&nbsp;std::ref(cont1),&nbsp;std::ref(cont2),&nbsp;3);&nbsp;
                                16. &nbsp;&nbsp;&nbsp;&nbsp;std::thread&nbsp;t2(exchange,&nbsp;std::ref(cont2),&nbsp;std::ref(cont1),&nbsp;6)&nbsp;
                                17. &nbsp;&nbsp;
                                18. &nbsp;&nbsp;&nbsp;&nbsp;t1.join();&nbsp;
                                19. &nbsp;&nbsp;&nbsp;&nbsp;t2.join();&nbsp;
                                20. &nbsp;&nbsp;
                                21. &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;&nbsp;
                                22. }&nbsp;
                                23. 要解决这个问题,可以使用std::lock来确保以避免发生死锁的方式来获取锁。

                                  讯享网

                                  1. void&nbsp;exchange(container&lt;int&gt;&&nbsp;cont1,&nbsp;container&lt;int&gt;&&nbsp;cont2,&nbsp;int&nbsp;value)&nbsp;
                                  2. {&nbsp;
                                  3. &nbsp;&nbsp;&nbsp;&nbsp;std::lock(cont1._lock,&nbsp;cont2._lock);&nbsp;
                                  4. &nbsp;&nbsp;
                                  5. &nbsp;&nbsp;&nbsp;&nbsp;cont1.remove(value);&nbsp;
                                  6. &nbsp;&nbsp;&nbsp;&nbsp;cont2.add(value);&nbsp;
                                  7. &nbsp;&nbsp;
                                  8. &nbsp;&nbsp;&nbsp;&nbsp;cont1._lock.unlock();&nbsp;
                                  9. &nbsp;&nbsp;&nbsp;&nbsp;cont2._lock.unlock();&nbsp;
                                  10. }&nbsp;
                                  11. #p#

                                    条件变量C++11 还提供了另外一种同步原语,就是条件变量,它能使一个或多个线程进入阻塞状态,直到接到另一个线程的通知,或者发生超时或虚假唤醒时,才退出阻塞.在头文件&lt;condition_variable&gt; 里对条件变量有两种实现:

                                    condition_variable:要求任何在等待该条件变量的线程必须先获取std::unique_lock锁。

                                    Condition_variable_any:是一种更加通用的实现,可以用于任意满足锁的基本条件的类型(该实现只要提供了lock()和 unlock()方法即可)。因为使用它花费的代价比较高(从性能和操作系统资源的角度来讲),所以只有在提供了必不可少的额外的灵活性的条件下才提倡使 用它。

                                    下面来讲讲条件变量的工作原理: 至少有一个线程在等待某个条件变为true。等待的线程必须先获取unique_lock 锁。该锁被传递给wait()方法,wait()方法会释放互斥量,并将线程挂起,直到条件变量接收到信号。收到信号后,线程会被唤醒,同时该锁也会被重 新获取。

                                    至少有一个线程发送信号使某个条件变为true。可以使用notify_one()来发送信号,同时唤醒一个正在等待该条件收到信号的处于阻塞状态的线程,或者用notify_all()来唤醒在等待该条件的所有线程。

                                    在多处理器系统中,因为一些复杂情况,要想完全预测到条件被唤醒并不容易,还会出现虚假唤醒的情况。就是说,在没人给条件变量发送信号的情况下,线程也可能会被唤醒。所以线程被唤醒后,还需要检测条件是否为true。因为可能会多次发生虚假唤醒,所以需要进行循环检测。

                                    下面代码是一个使用条件变量来同步线程的例子:几个工作线程运行时可能会产生错误并将错误代码放到队列里。记录线程会从队列里取出错误代码并输出它 们来处理这些错误。发生错误的时候,工作线程会给记录线程发信号。记录线程一直在等待条件变量接收信号。为了避免发生虚假唤醒,该等待过程在循环检测条件 的布尔值。

                                    &nbsp;

                                    1. #include&nbsp;&lt;thread&gt;&nbsp;
                                    2. #include&nbsp;&lt;mutex&gt;&nbsp;
                                    3. #include&nbsp;&lt;condition_variable&gt;&nbsp;
                                    4. #include&nbsp;&lt;iostream&gt;&nbsp;
                                    5. #include&nbsp;&lt;queue&gt;&nbsp;
                                    6. #include&nbsp;&lt;random&gt;&nbsp;
                                    7. &nbsp;&nbsp;
                                    8. std::mutex&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_lockprint;&nbsp;
                                    9. std::mutex&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_lockqueue;&nbsp;
                                    10. std::condition_variable&nbsp;g_queuecheck;&nbsp;
                                    11. std::queue&lt;int&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_codes;&nbsp;
                                    12. bool&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_done;&nbsp;
                                    13. bool&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_notified;&nbsp;
                                    14. &nbsp;&nbsp;
                                    15. void&nbsp;workerfunc(int&nbsp;id,&nbsp;std::mt19937&&nbsp;generator)&nbsp;
                                    16. {&nbsp;
                                    17. &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;print&nbsp;a&nbsp;starting&nbsp;message&nbsp;
                                    18. &nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
                                    19. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::unique_lock&lt;std::mutex&gt;&nbsp;locker(g_lockprint);&nbsp;
                                    20. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;&lt;&lt;&nbsp;”[worker&nbsp;“&nbsp;&lt;&lt;&nbsp;id&nbsp;&lt;&lt;&nbsp;”] running…”&nbsp;&lt;&lt;&nbsp;std::endl;&nbsp;
                                    21. &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
                                    22. &nbsp;&nbsp;
                                    23. &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;simulate&nbsp;work&nbsp;
                                    24. &nbsp;&nbsp;&nbsp;&nbsp;std::this_thread::sleep_for(std::chrono::seconds(1&nbsp;+&nbsp;generator()&nbsp;%&nbsp;5));&nbsp;
                                    25. &nbsp;&nbsp;
                                    26. &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;simulate&nbsp;error&nbsp;
                                    27. &nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;errorcode&nbsp;=&nbsp;id*100+1;&nbsp;
                                    28. &nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
                                    29. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::unique_lock&lt;std::mutex&gt;&nbsp;locker(g_lockprint);&nbsp;
                                    30. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;&nbsp;&lt;&lt;&nbsp;”[worker&nbsp;“&nbsp;&lt;&lt;&nbsp;id&nbsp;&lt;&lt;&nbsp;”] an&nbsp;error&nbsp;occurred:&nbsp;“&nbsp;&lt;&lt;&nbsp;errorcode&nbsp;&lt;&lt;&nbsp;std::endl;&nbsp;
                                    31. &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
                                    32. &nbsp;&nbsp;
                                    33. &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;notify&nbsp;error&nbsp;to&nbsp;be&nbsp;logged&nbsp;
                                    34. &nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
                                    35. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::unique_lock&lt;std::mutex&gt;&nbsp;locker(g_lockqueue);&nbsp;
                                    36. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_codes.push(errorcode);&nbsp;
                                    37. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_notified&nbsp;=&nbsp;true;&nbsp;
                                    38. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_queuecheck.notify_one();&nbsp;
                                    39. &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
                                    40. }&nbsp;
                                    41. &nbsp;&nbsp;
                                    42. void&nbsp;loggerfunc()&nbsp;
                                    43. {&nbsp;
                                    44. &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;print&nbsp;a&nbsp;starting&nbsp;message&nbsp;
                                    45. &nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
                                    46. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::unique_lock&lt;std::mutex&gt;&nbsp;locker(g_lockprint);&nbsp;
                                    47. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;&lt;&lt;&nbsp;”[logger] running…”&nbsp;&lt;&lt;&nbsp;std::endl;&nbsp;
                                    48. &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
                                    49. &nbsp;&nbsp;
                                    50. &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;loop&nbsp;until&nbsp;end&nbsp;is&nbsp;signaled&nbsp;
                                    51. &nbsp;&nbsp;&nbsp;&nbsp;while(!g_done)&nbsp;
                                    52. &nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
                                    53. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::unique_lock&lt;std::mutex&gt;&nbsp;locker(g_lockqueue);&nbsp;
                                    54. &nbsp;&nbsp;
                                    55. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(!g_notified)&nbsp;//&nbsp;used&nbsp;to&nbsp;avoid&nbsp;spurious&nbsp;wakeups&nbsp;
                                    56. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
                                    57. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_queuecheck.wait(locker);&nbsp;
                                    58. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
                                    59. &nbsp;&nbsp;
                                    60. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;if&nbsp;there&nbsp;are&nbsp;error&nbsp;codes&nbsp;in&nbsp;the&nbsp;queue&nbsp;process&nbsp;them&nbsp;
                                    61. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(!g_codes.empty())&nbsp;
                                    62. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
                                    63. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::unique_lock&lt;std::mutex&gt;&nbsp;locker(g_lockprint);&nbsp;
                                    64. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;&lt;&lt;&nbsp;”[logger] processing&nbsp;error:&nbsp;&nbsp;“&nbsp;&lt;&lt;&nbsp;g_codes.front()&nbsp;&nbsp;&lt;&lt;&nbsp;std::endl;&nbsp;
                                    65. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_codes.pop();&nbsp;
                                    66. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
                                    67. &nbsp;&nbsp;
                                    68. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_notified&nbsp;=&nbsp;false;&nbsp;
                                    69. &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
                                    70. }&nbsp;
                                    71. &nbsp;&nbsp;
                                    72. int&nbsp;main()&nbsp;
                                    73. {&nbsp;
                                    74. &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;initialize&nbsp;a&nbsp;random&nbsp;generator&nbsp;
                                    75. &nbsp;&nbsp;&nbsp;&nbsp;std::mt19937&nbsp;generator((unsigned&nbsp;int)std::chrono::system_clock::now().time_since_epoch().count());&nbsp;
                                    76. &nbsp;&nbsp;
                                    77. &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;start&nbsp;the&nbsp;logger&nbsp;
                                    78. &nbsp;&nbsp;&nbsp;&nbsp;std::thread&nbsp;loggerthread(loggerfunc);&nbsp;
                                    79. &nbsp;&nbsp;
                                    80. &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;start&nbsp;the&nbsp;working&nbsp;threads&nbsp;
                                    81. &nbsp;&nbsp;&nbsp;&nbsp;std::vector&lt;std::thread&gt;&nbsp;threads;&nbsp;
                                    82. &nbsp;&nbsp;&nbsp;&nbsp;for(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;5;&nbsp;++i)&nbsp;
                                    83. &nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
                                    84. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;threads.push_back(std::thread(workerfunc,&nbsp;i+1,&nbsp;std::ref(generator)));&nbsp;
                                    85. &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
                                    86. &nbsp;&nbsp;
                                    87. &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;work&nbsp;for&nbsp;the&nbsp;workers&nbsp;to&nbsp;finish&nbsp;
                                    88. &nbsp;&nbsp;&nbsp;&nbsp;for(auto&&nbsp;t&nbsp;:&nbsp;threads)&nbsp;
                                    89. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t.join();&nbsp;
                                    90. &nbsp;&nbsp;
                                    91. &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;notify&nbsp;the&nbsp;logger&nbsp;to&nbsp;finish&nbsp;and&nbsp;wait&nbsp;for&nbsp;it&nbsp;
                                    92. &nbsp;&nbsp;&nbsp;&nbsp;g_done&nbsp;=&nbsp;true;&nbsp;
                                    93. &nbsp;&nbsp;&nbsp;&nbsp;loggerthread.join();&nbsp;
                                    94. &nbsp;&nbsp;
                                    95. &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;&nbsp;
                                    96. }&nbsp;
                                    97. 运行上述代码,输出结果如下(注意每次运行,输出结果都不一样;因为每个工作线程运行时都有一个随机的休眠时间)。

                                      讯享网

                                      1. [logger]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;running…&nbsp;
                                      2. [worker&nbsp;1]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;running…&nbsp;
                                      3. [worker&nbsp;2]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;running…&nbsp;
                                      4. [worker&nbsp;3]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;running…&nbsp;
                                      5. [worker&nbsp;4]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;running…&nbsp;
                                      6. [worker&nbsp;5]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;running…&nbsp;
                                      7. [worker&nbsp;1]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;an&nbsp;error&nbsp;occurred:&nbsp;101&nbsp;
                                      8. [worker&nbsp;2]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;an&nbsp;error&nbsp;occurred:&nbsp;201&nbsp;
                                      9. [logger]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;processing&nbsp;error:&nbsp;&nbsp;101&nbsp;
                                      10. [logger]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;processing&nbsp;error:&nbsp;&nbsp;201&nbsp;
                                      11. [worker&nbsp;5]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;an&nbsp;error&nbsp;occurred:&nbsp;501&nbsp;
                                      12. [logger]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;processing&nbsp;error:&nbsp;&nbsp;501&nbsp;
                                      13. [worker&nbsp;3]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;an&nbsp;error&nbsp;occurred:&nbsp;301&nbsp;
                                      14. [worker&nbsp;4]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;an&nbsp;error&nbsp;occurred:&nbsp;401&nbsp;
                                      15. [logger]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;processing&nbsp;error:&nbsp;&nbsp;301&nbsp;
                                      16. [logger]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;processing&nbsp;error:&nbsp;&nbsp;401&nbsp;
                                      17. 上面看到的wait()方法有两个重载:

                                        • *个重载带有锁unique_lock;这个重载方法可以释放锁,阻塞线程,并把线程添加到正在等待这一条件变量的线程队列里面。当该条件变量收到信号或者发生虚假唤醒时,线程就会被唤醒。它们其中任何一个发生时,锁都会被重新获取,函数返回。
                                        • 第二个重载除了带有锁unique_lock外,还带有循环判定直到返回false值;这个重载是用来避免发生虚假唤醒。它基本上等价于下面的语句:

                                        1. while(!predicate())&nbsp;
                                        2. &nbsp;&nbsp;&nbsp;wait(lock);&nbsp;
                                        3. 因此在上面的例子中,通过使用重载的wait()方法以及验证队列状态的判断(空或不空),就可以避免使用布尔变量g_notified了。

                                          讯享网

                                          1. void&nbsp;workerfunc(int&nbsp;id,&nbsp;std::mt19937&&nbsp;generator)&nbsp;
                                          2. {&nbsp;
                                          3. &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;print&nbsp;a&nbsp;starting&nbsp;message&nbsp;
                                          4. &nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
                                          5. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::unique_lock&lt;std::mutex&gt;&nbsp;locker(g_lockprint);&nbsp;
                                          6. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;&lt;&lt;&nbsp;”[worker&nbsp;“&nbsp;&lt;&lt;&nbsp;id&nbsp;&lt;&lt;&nbsp;”] running…”&nbsp;&lt;&lt;&nbsp;std::endl;&nbsp;
                                          7. &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
                                          8. &nbsp;&nbsp;
                                          9. &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;simulate&nbsp;work&nbsp;
                                          10. &nbsp;&nbsp;&nbsp;&nbsp;std::this_thread::sleep_for(std::chrono::seconds(1&nbsp;+&nbsp;generator()&nbsp;%&nbsp;5));&nbsp;
                                          11. &nbsp;&nbsp;
                                          12. &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;simulate&nbsp;error&nbsp;
                                          13. &nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;errorcode&nbsp;=&nbsp;id*100+1;&nbsp;
                                          14. &nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
                                          15. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::unique_lock&lt;std::mutex&gt;&nbsp;locker(g_lockprint);&nbsp;
                                          16. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;&lt;&lt;&nbsp;”[worker&nbsp;“&nbsp;&lt;&lt;&nbsp;id&nbsp;&lt;&lt;&nbsp;”] an&nbsp;error&nbsp;occurred:&nbsp;“&nbsp;&lt;&lt;&nbsp;errorcode&nbsp;&lt;&lt;&nbsp;std::endl;&nbsp;
                                          17. &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
                                          18. &nbsp;&nbsp;
                                          19. &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;notify&nbsp;error&nbsp;to&nbsp;be&nbsp;logged&nbsp;
                                          20. &nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
                                          21. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::unique_lock&lt;std::mutex&gt;&nbsp;locker(g_lockqueue);&nbsp;
                                          22. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_codes.push(errorcode);&nbsp;
                                          23. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_queuecheck.notify_one();&nbsp;
                                          24. &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
                                          25. }&nbsp;
                                          26. &nbsp;&nbsp;
                                          27. void&nbsp;loggerfunc()&nbsp;
                                          28. {&nbsp;
                                          29. &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;print&nbsp;a&nbsp;starting&nbsp;message&nbsp;
                                          30. &nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
                                          31. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::unique_lock&lt;std::mutex&gt;&nbsp;locker(g_lockprint);&nbsp;
                                          32. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;&lt;&lt;&nbsp;”[logger] running…”&nbsp;&lt;&lt;&nbsp;std::endl;&nbsp;
                                          33. &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
                                          34. &nbsp;&nbsp;
                                          35. &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;loop&nbsp;until&nbsp;end&nbsp;is&nbsp;signaled&nbsp;
                                          36. &nbsp;&nbsp;&nbsp;&nbsp;while(!g_done)&nbsp;
                                          37. &nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
                                          38. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::unique_lock&lt;std::mutex&gt;&nbsp;locker(g_lockqueue);&nbsp;
                                          39. &nbsp;&nbsp;
                                          40. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_queuecheck.wait(locker,&nbsp;&{return&nbsp;!g_codes.empty();});&nbsp;
                                          41. &nbsp;&nbsp;
                                          42. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;if&nbsp;there&nbsp;are&nbsp;error&nbsp;codes&nbsp;in&nbsp;the&nbsp;queue&nbsp;process&nbsp;them&nbsp;
                                          43. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(!g_codes.empty())&nbsp;
                                          44. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;
                                          45. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::unique_lock&lt;std::mutex&gt;&nbsp;locker(g_lockprint);&nbsp;
                                          46. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;&lt;&lt;&nbsp;”[logger] processing&nbsp;error:&nbsp;&nbsp;“&nbsp;&lt;&lt;&nbsp;g_codes.front()&nbsp;&lt;&lt;&nbsp;std::endl;&nbsp;
                                          47. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_codes.pop();&nbsp;
                                          48. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
                                          49. &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
                                          50. }&nbsp;
                                          51. 除了这个重载的wait()方法,还有另外两个类似的重载方法,也带有避免虚假唤醒的判定。

                                            • Wait_for: 在条件变量收到信号或者指定的超时发生前,线程一直处于阻塞状态;
                                            • Wait_until:在条件变量收到信号或者指定的时刻到达之前,线程一直处于阻塞状态。

                                            这两个函数的不带有判定的重载返回cv_status状态,用来表明发生超时或者线程被唤醒是因为条件变量收到信号或者发生虚假唤醒。

                                            该标准还提供了一个函数notify_all_at_thread_exit,它实现了一个机制,通知其他线程给定线程已经运行结束,并销毁所有的 thread_local对象。该函数的引进是因为在使用了thread_local后,采用除join()之外的其他机制来等待线程会导致不正确甚至致 命的行为发生。

                                            因为thread_local的析构函数会在等待中的线程恢复执行和可能执行结束的情况下被调用(可参考N3070和N2880得知更多信息)。

                                            通常情况下,对这个函数的调用必须在线程生成之前。下面的例子描述了如何使用notify_all_at_thread_exit和condition_variable共同完成对两个线程的同步操作:

                                            1. std::mutex&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_lockprint;&nbsp;
                                            2. std::mutex&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_lock;&nbsp;
                                            3. std::condition_variable&nbsp;g_signal;&nbsp;
                                            4. bool&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_done;&nbsp;
                                            5. &nbsp;&nbsp;
                                            6. void&nbsp;workerfunc(std::mt19937&&nbsp;generator)&nbsp;
                                            7. {&nbsp;
                                            8. &nbsp;&nbsp;&nbsp;{&nbsp;
                                            9. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::unique_lock&lt;std::mutex&gt;&nbsp;locker(g_lockprint);&nbsp;
                                            10. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;&lt;&lt;&nbsp;“worker&nbsp;running…”&nbsp;&lt;&lt;&nbsp;std::endl;&nbsp;
                                            11. &nbsp;&nbsp;&nbsp;}&nbsp;
                                            12. &nbsp;&nbsp;
                                            13. &nbsp;&nbsp;&nbsp;std::this_thread::sleep_for(std::chrono::seconds(1&nbsp;+&nbsp;generator()&nbsp;%&nbsp;5));&nbsp;
                                            14. &nbsp;&nbsp;
                                            15. &nbsp;&nbsp;&nbsp;{&nbsp;
                                            16. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::unique_lock&lt;std::mutex&gt;&nbsp;locker(g_lockprint);&nbsp;
                                            17. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;&lt;&lt;&nbsp;“worker&nbsp;finished…”&nbsp;&lt;&lt;&nbsp;std::endl;&nbsp;
                                            18. &nbsp;&nbsp;&nbsp;}&nbsp;
                                            19. &nbsp;&nbsp;
                                            20. &nbsp;&nbsp;&nbsp;std::unique_lock&lt;std::mutex&gt;&nbsp;lock(g_lock);&nbsp;
                                            21. &nbsp;&nbsp;&nbsp;g_done&nbsp;=&nbsp;true;&nbsp;
                                            22. &nbsp;&nbsp;&nbsp;std::notify_all_at_thread_exit(g_signal,&nbsp;std::move(lock));&nbsp;
                                            23. }&nbsp;
                                            24. &nbsp;&nbsp;
                                            25. int&nbsp;main()&nbsp;
                                            26. {&nbsp;
                                            27. &nbsp;&nbsp;&nbsp;//&nbsp;initialize&nbsp;a&nbsp;random&nbsp;generator&nbsp;
                                            28. &nbsp;&nbsp;&nbsp;std::mt19937&nbsp;generator((unsigned&nbsp;int)std::chrono::system_clock::now().time_since_epoch().count());&nbsp;
                                            29. &nbsp;&nbsp;
                                            30. &nbsp;&nbsp;&nbsp;std::cout&nbsp;&lt;&lt;&nbsp;“main&nbsp;running…”&nbsp;&lt;&lt;&nbsp;std::endl;&nbsp;
                                            31. &nbsp;&nbsp;
                                            32. &nbsp;&nbsp;&nbsp;std::thread&nbsp;worker(workerfunc,&nbsp;std::ref(generator));&nbsp;
                                            33. &nbsp;&nbsp;&nbsp;worker.detach();&nbsp;
                                            34. &nbsp;&nbsp;
                                            35. &nbsp;&nbsp;&nbsp;std::cout&nbsp;&lt;&lt;&nbsp;“main&nbsp;crunching…”&nbsp;&lt;&lt;&nbsp;std::endl;&nbsp;
                                            36. &nbsp;&nbsp;
                                            37. &nbsp;&nbsp;&nbsp;std::this_thread::sleep_for(std::chrono::seconds(1&nbsp;+&nbsp;generator()&nbsp;%&nbsp;5));&nbsp;
                                            38. &nbsp;&nbsp;
                                            39. &nbsp;&nbsp;&nbsp;{&nbsp;
                                            40. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::unique_lock&lt;std::mutex&gt;&nbsp;locker(g_lockprint);&nbsp;
                                            41. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;&lt;&lt;&nbsp;“main&nbsp;waiting&nbsp;for&nbsp;worker…”&nbsp;&lt;&lt;&nbsp;std::endl;&nbsp;
                                            42. &nbsp;&nbsp;&nbsp;}&nbsp;
                                            43. &nbsp;&nbsp;
                                            44. &nbsp;&nbsp;&nbsp;std::unique_lock&lt;std::mutex&gt;&nbsp;lock(g_lock);&nbsp;
                                            45. &nbsp;&nbsp;&nbsp;while(!g_done)&nbsp;//&nbsp;avoid&nbsp;spurious&nbsp;wake-ups&nbsp;
                                            46. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_signal.wait(lock);&nbsp;
                                            47. &nbsp;&nbsp;
                                            48. &nbsp;&nbsp;&nbsp;std::cout&nbsp;&lt;&lt;&nbsp;“main&nbsp;finished…”&nbsp;&lt;&lt;&nbsp;std::endl;&nbsp;
                                            49. &nbsp;&nbsp;
                                            50. &nbsp;&nbsp;&nbsp;return&nbsp;0;&nbsp;
                                            51. }&nbsp;
                                            52. 如果工作线程在主线程执行结束之前结束,输出结果将如下:

                                              讯享网

                                              1. main&nbsp;running…&nbsp;
                                              2. worker&nbsp;running…&nbsp;
                                              3. main&nbsp;crunching…&nbsp;
                                              4. worker&nbsp;finished…&nbsp;
                                              5. main&nbsp;waiting&nbsp;for&nbsp;worker…&nbsp;
                                              6. main&nbsp;finished…&nbsp;
                                              7. 如果主线程比工作线程更早结束,输出结果将如下:

                                                1. main&nbsp;running…&nbsp;
                                                2. worker&nbsp;running…&nbsp;
                                                3. main&nbsp;crunching…&nbsp;
                                                4. main&nbsp;waiting&nbsp;for&nbsp;worker…&nbsp;
                                                5. worker&nbsp;finished…&nbsp;
                                                6. main&nbsp;finished…&nbsp;
                                                7. 结束语

                                                  C++11标准可以让C++开发者以一种标准的,独立平台的方式来编写多线程。这篇文章大概讲述了该标准所支持的线程和同步机制。头文 件&lt;thread&gt;提供了thread类(和一些帮助函数),表明thread类是一个可执行线程。头文件&lt;mutex&gt;提供了 几种互斥量的实现和对线程进行同步访问的封装类。头文件&lt;condition_variable&gt;提供了条件变量的两种实现,这些实现使一个 或多个线程一直处于阻塞状态,直到接收到其他线程的通知,或发生超时或者有虚假唤醒发生时才会被唤醒。推荐读者朋友可以阅读其他资料来获取更多的详细信 息。

                                                  原文链接:http://blog.jobbole.com/44409/


                                                  小讯
                                                  上一篇 2025-04-28 17:21
                                                  下一篇 2025-05-12 16:25

                                                  相关推荐

                                                  版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
                                                  如需转载请保留出处:https://51itzy.com/kjqy/205291.html