lost_notif_pass.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. //===----------------------------------------------------------------------===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is dual licensed under the MIT and the University of Illinois Open
  6. // Source Licenses. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. // Copyright (C) 2017 Austin J. Beer
  10. //
  11. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  12. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  13. // <boost/thread/condition_variable>
  14. // class condition_variable;
  15. // condition_variable(const condition_variable&) = delete;
  16. #include <iostream>
  17. #include <boost/thread/condition_variable.hpp>
  18. #include <boost/thread/mutex.hpp>
  19. #include <boost/thread/thread.hpp>
  20. #include <boost/detail/lightweight_test.hpp>
  21. #include <cassert>
  22. // Summary of each test:
  23. // 1. Start the test thread and wait for it to start up.
  24. // The test thread waits for the flag to be set using a large timeout.
  25. // 2. The main thread takes the lock and then sleeps for a long time while holding
  26. // the lock before setting the flag and calling notify_one(). If the wait
  27. // function being tested is polling pthread_cond_timedwait() internally, any
  28. // notifications sent after pthread_cond_timedwait() times out but before it can
  29. // reacquire the lock may be "lost". pthread_cond_timedwait() will report that
  30. // it timed out and the wait function may incorrectly assume that no
  31. // notification was received. This test ensures that that doesn't happen.
  32. // 3. Measure how it takes the test thread to return. If it received the
  33. // notification, it will return fairly quickly. If it missed the notification,
  34. // the test thread won't return until the wait function being tested times out.
  35. //------------------------------------------------------------------------------
  36. boost::condition_variable cv;
  37. boost::mutex mut;
  38. bool flag;
  39. bool waiting;
  40. bool flagIsSet()
  41. {
  42. return flag;
  43. }
  44. bool threadIsWaiting()
  45. {
  46. return waiting;
  47. }
  48. //------------------------------------------------------------------------------
  49. #ifdef BOOST_THREAD_USES_DATETIME
  50. boost::posix_time::milliseconds posix_wait_time(1000);
  51. template <typename F>
  52. void test_posix_wait_function(F f)
  53. {
  54. flag = false;
  55. waiting = false;
  56. boost::thread t(f);
  57. while (!threadIsWaiting())
  58. {
  59. boost::this_thread::sleep(boost::posix_time::milliseconds(1));
  60. }
  61. boost::unique_lock<boost::mutex> lk(mut);
  62. boost::this_thread::sleep(boost::posix_time::milliseconds(500));
  63. boost::posix_time::ptime t0 = boost::posix_time::microsec_clock::universal_time();
  64. flag = true;
  65. cv.notify_one();
  66. lk.unlock();
  67. t.join();
  68. boost::posix_time::ptime t1 = boost::posix_time::microsec_clock::universal_time();
  69. BOOST_TEST(t1 - t0 < boost::posix_time::milliseconds(250));
  70. }
  71. //------------------------------------------------------------------------------
  72. void timed_wait_absolute_without_pred()
  73. {
  74. boost::unique_lock<boost::mutex> lk(mut);
  75. waiting = true;
  76. while (!flagIsSet())
  77. {
  78. cv.timed_wait(lk, boost::posix_time::microsec_clock::universal_time() + posix_wait_time);
  79. }
  80. }
  81. void timed_wait_absolute_with_pred()
  82. {
  83. boost::unique_lock<boost::mutex> lk(mut);
  84. waiting = true;
  85. cv.timed_wait(lk, boost::posix_time::microsec_clock::universal_time() + posix_wait_time, flagIsSet);
  86. }
  87. //------------------------------------------------------------------------------
  88. void timed_wait_relative_without_pred()
  89. {
  90. boost::unique_lock<boost::mutex> lk(mut);
  91. waiting = true;
  92. while (!flagIsSet())
  93. {
  94. cv.timed_wait(lk, posix_wait_time);
  95. }
  96. }
  97. void timed_wait_relative_with_pred()
  98. {
  99. boost::unique_lock<boost::mutex> lk(mut);
  100. waiting = true;
  101. cv.timed_wait(lk, posix_wait_time, flagIsSet);
  102. }
  103. #else
  104. #error "Test not applicable: BOOST_THREAD_USES_DATETIME not defined for this platform as not supported"
  105. #endif
  106. //------------------------------------------------------------------------------
  107. #ifdef BOOST_THREAD_USES_CHRONO
  108. boost::chrono::milliseconds chrono_wait_time(1000);
  109. template <typename F>
  110. void test_chrono_wait_function(F f)
  111. {
  112. flag = false;
  113. waiting = false;
  114. boost::thread t(f);
  115. while (!threadIsWaiting())
  116. {
  117. boost::this_thread::sleep_for(boost::chrono::milliseconds(1));
  118. }
  119. boost::unique_lock<boost::mutex> lk(mut);
  120. boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
  121. boost::chrono::steady_clock::time_point t0 = boost::chrono::steady_clock::now();
  122. flag = true;
  123. cv.notify_one();
  124. lk.unlock();
  125. t.join();
  126. boost::chrono::steady_clock::time_point t1 = boost::chrono::steady_clock::now();
  127. BOOST_TEST(t1 - t0 < boost::chrono::milliseconds(250));
  128. }
  129. //------------------------------------------------------------------------------
  130. void wait_until_system_without_pred()
  131. {
  132. boost::unique_lock<boost::mutex> lk(mut);
  133. waiting = true;
  134. while (!flagIsSet())
  135. {
  136. cv.wait_until(lk, boost::chrono::system_clock::now() + chrono_wait_time);
  137. }
  138. }
  139. void wait_until_system_with_pred()
  140. {
  141. boost::unique_lock<boost::mutex> lk(mut);
  142. waiting = true;
  143. cv.wait_until(lk, boost::chrono::system_clock::now() + chrono_wait_time, flagIsSet);
  144. }
  145. //------------------------------------------------------------------------------
  146. void wait_until_steady_without_pred()
  147. {
  148. boost::unique_lock<boost::mutex> lk(mut);
  149. waiting = true;
  150. while (!flagIsSet())
  151. {
  152. cv.wait_until(lk, boost::chrono::steady_clock::now() + chrono_wait_time);
  153. }
  154. }
  155. void wait_until_steady_with_pred()
  156. {
  157. boost::unique_lock<boost::mutex> lk(mut);
  158. waiting = true;
  159. cv.wait_until(lk, boost::chrono::steady_clock::now() + chrono_wait_time, flagIsSet);
  160. }
  161. //------------------------------------------------------------------------------
  162. void wait_for_without_pred()
  163. {
  164. boost::unique_lock<boost::mutex> lk(mut);
  165. waiting = true;
  166. while (!flagIsSet())
  167. {
  168. cv.wait_for(lk, chrono_wait_time);
  169. }
  170. }
  171. void wait_for_with_pred()
  172. {
  173. boost::unique_lock<boost::mutex> lk(mut);
  174. waiting = true;
  175. cv.wait_for(lk, chrono_wait_time, flagIsSet);
  176. }
  177. #else
  178. #error "Test not applicable: BOOST_THREAD_USES_CHRONO not defined for this platform as not supported"
  179. #endif
  180. //------------------------------------------------------------------------------
  181. int main()
  182. {
  183. #ifdef BOOST_THREAD_USES_DATETIME
  184. test_posix_wait_function(timed_wait_absolute_without_pred);
  185. test_posix_wait_function(timed_wait_absolute_with_pred);
  186. test_posix_wait_function(timed_wait_relative_without_pred);
  187. test_posix_wait_function(timed_wait_relative_with_pred);
  188. #endif
  189. #ifdef BOOST_THREAD_USES_CHRONO
  190. test_chrono_wait_function(wait_until_system_without_pred);
  191. test_chrono_wait_function(wait_until_system_with_pred);
  192. test_chrono_wait_function(wait_until_steady_without_pred);
  193. test_chrono_wait_function(wait_until_steady_with_pred);
  194. test_chrono_wait_function(wait_for_without_pred);
  195. test_chrono_wait_function(wait_for_with_pred);
  196. #endif
  197. return boost::report_errors();
  198. }