test_condition_variable_post.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. // Copyright Oliver Kowalke 2013.
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // (See accompanying file LICENSE_1_0.txt or copy at
  4. // http://www.boost.org/LICENSE_1_0.txt)
  5. //
  6. // This test is based on the tests of Boost.Thread
  7. #include <chrono>
  8. #include <cstdio>
  9. #include <cstdlib>
  10. #include <iostream>
  11. #include <map>
  12. #include <mutex>
  13. #include <stdexcept>
  14. #include <vector>
  15. #include <boost/test/unit_test.hpp>
  16. #include <boost/fiber/all.hpp>
  17. typedef std::chrono::nanoseconds ns;
  18. typedef std::chrono::milliseconds ms;
  19. int value1 = 0;
  20. inline
  21. std::chrono::system_clock::time_point delay(int secs, int msecs = 0, int /*nsecs*/ = 0) {
  22. std::chrono::system_clock::time_point t = std::chrono::system_clock::now();
  23. t += std::chrono::seconds( secs);
  24. t += std::chrono::milliseconds( msecs);
  25. //t += std::chrono::nanoseconds( nsecs);
  26. return t;
  27. }
  28. struct condition_test_data {
  29. condition_test_data() : notified(0), awoken(0) { }
  30. boost::fibers::mutex mutex;
  31. boost::fibers::condition_variable cond;
  32. int notified;
  33. int awoken;
  34. };
  35. void condition_test_fiber(condition_test_data* data) {
  36. std::unique_lock<boost::fibers::mutex> lock(data->mutex);
  37. BOOST_CHECK(lock ? true : false);
  38. while (!(data->notified > 0))
  39. data->cond.wait(lock);
  40. BOOST_CHECK(lock ? true : false);
  41. data->awoken++;
  42. }
  43. struct cond_predicate {
  44. cond_predicate(int& var, int val) : _var(var), _val(val) { }
  45. bool operator()() { return _var == _val; }
  46. int& _var;
  47. int _val;
  48. private:
  49. void operator=(cond_predicate&);
  50. };
  51. void notify_one_fn( boost::fibers::condition_variable & cond) {
  52. cond.notify_one();
  53. }
  54. void notify_all_fn( boost::fibers::condition_variable & cond) {
  55. cond.notify_all();
  56. }
  57. void wait_fn(
  58. boost::fibers::mutex & mtx,
  59. boost::fibers::condition_variable & cond) {
  60. std::unique_lock< boost::fibers::mutex > lk( mtx);
  61. cond.wait( lk);
  62. ++value1;
  63. }
  64. void test_one_waiter_notify_one() {
  65. value1 = 0;
  66. boost::fibers::mutex mtx;
  67. boost::fibers::condition_variable cond;
  68. boost::fibers::fiber f1(
  69. boost::fibers::launch::post,
  70. wait_fn,
  71. std::ref( mtx),
  72. std::ref( cond) );
  73. BOOST_CHECK_EQUAL( 0, value1);
  74. boost::fibers::fiber f2(
  75. boost::fibers::launch::post,
  76. notify_one_fn,
  77. std::ref( cond) );
  78. BOOST_CHECK_EQUAL( 0, value1);
  79. f1.join();
  80. f2.join();
  81. BOOST_CHECK_EQUAL( 1, value1);
  82. }
  83. void test_two_waiter_notify_one() {
  84. value1 = 0;
  85. boost::fibers::mutex mtx;
  86. boost::fibers::condition_variable cond;
  87. boost::fibers::fiber f1(
  88. boost::fibers::launch::post,
  89. wait_fn,
  90. std::ref( mtx),
  91. std::ref( cond) );
  92. BOOST_CHECK_EQUAL( 0, value1);
  93. boost::fibers::fiber f2(
  94. boost::fibers::launch::post,
  95. wait_fn,
  96. std::ref( mtx),
  97. std::ref( cond) );
  98. BOOST_CHECK_EQUAL( 0, value1);
  99. boost::fibers::fiber f3(
  100. boost::fibers::launch::post,
  101. notify_one_fn,
  102. std::ref( cond) );
  103. BOOST_CHECK_EQUAL( 0, value1);
  104. boost::fibers::fiber f4(
  105. boost::fibers::launch::post,
  106. notify_one_fn,
  107. std::ref( cond) );
  108. BOOST_CHECK_EQUAL( 0, value1);
  109. f1.join();
  110. f2.join();
  111. f3.join();
  112. f4.join();
  113. BOOST_CHECK_EQUAL( 2, value1);
  114. }
  115. void test_two_waiter_notify_all() {
  116. value1 = 0;
  117. boost::fibers::mutex mtx;
  118. boost::fibers::condition_variable cond;
  119. boost::fibers::fiber f1(
  120. boost::fibers::launch::post,
  121. wait_fn,
  122. std::ref( mtx),
  123. std::ref( cond) );
  124. BOOST_CHECK_EQUAL( 0, value1);
  125. boost::fibers::fiber f2(
  126. boost::fibers::launch::post,
  127. wait_fn,
  128. std::ref( mtx),
  129. std::ref( cond) );
  130. BOOST_CHECK_EQUAL( 0, value1);
  131. boost::fibers::fiber f3(
  132. boost::fibers::launch::post,
  133. notify_all_fn,
  134. std::ref( cond) );
  135. BOOST_CHECK_EQUAL( 0, value1);
  136. boost::fibers::fiber f4(
  137. boost::fibers::launch::post,
  138. wait_fn,
  139. std::ref( mtx),
  140. std::ref( cond) );
  141. BOOST_CHECK_EQUAL( 0, value1);
  142. boost::fibers::fiber f5(
  143. boost::fibers::launch::post,
  144. notify_all_fn,
  145. std::ref( cond) );
  146. BOOST_CHECK_EQUAL( 0, value1);
  147. f1.join();
  148. f2.join();
  149. f3.join();
  150. f4.join();
  151. f5.join();
  152. BOOST_CHECK_EQUAL( 3, value1);
  153. }
  154. int test1 = 0;
  155. int test2 = 0;
  156. int runs = 0;
  157. void fn1( boost::fibers::mutex & m, boost::fibers::condition_variable & cv) {
  158. std::unique_lock< boost::fibers::mutex > lk( m);
  159. BOOST_CHECK(test2 == 0);
  160. test1 = 1;
  161. cv.notify_one();
  162. while (test2 == 0) {
  163. cv.wait(lk);
  164. }
  165. BOOST_CHECK(test2 != 0);
  166. }
  167. void fn2( boost::fibers::mutex & m, boost::fibers::condition_variable & cv) {
  168. std::unique_lock< boost::fibers::mutex > lk( m);
  169. BOOST_CHECK(test2 == 0);
  170. test1 = 1;
  171. cv.notify_one();
  172. std::chrono::system_clock::time_point t0 = std::chrono::system_clock::now();
  173. std::chrono::system_clock::time_point t = t0 + ms(250);
  174. int count=0;
  175. while (test2 == 0 && cv.wait_until(lk, t) == boost::fibers::cv_status::no_timeout)
  176. count++;
  177. std::chrono::system_clock::time_point t1 = std::chrono::system_clock::now();
  178. if (runs == 0) {
  179. BOOST_CHECK(t1 - t0 < ms(250));
  180. BOOST_CHECK(test2 != 0);
  181. } else {
  182. BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100+1000));
  183. BOOST_CHECK(test2 == 0);
  184. }
  185. ++runs;
  186. }
  187. class Pred {
  188. int & i_;
  189. public:
  190. explicit Pred(int& i) :
  191. i_(i)
  192. {}
  193. bool operator()()
  194. { return i_ != 0; }
  195. };
  196. void fn3( boost::fibers::mutex & m, boost::fibers::condition_variable & cv) {
  197. std::unique_lock< boost::fibers::mutex > lk( m);
  198. BOOST_CHECK(test2 == 0);
  199. test1 = 1;
  200. cv.notify_one();
  201. std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
  202. std::chrono::steady_clock::time_point t = t0 + ms(250);
  203. bool r = cv.wait_until(lk, t, Pred(test2));
  204. std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
  205. if (runs == 0) {
  206. BOOST_CHECK(t1 - t0 < ms(250));
  207. BOOST_CHECK(test2 != 0);
  208. BOOST_CHECK(r);
  209. } else {
  210. BOOST_CHECK(t1 - t0 - ms(250) < ms(250+100));
  211. BOOST_CHECK(test2 == 0);
  212. BOOST_CHECK(!r);
  213. }
  214. ++runs;
  215. }
  216. void fn4( boost::fibers::mutex & m, boost::fibers::condition_variable & cv) {
  217. std::unique_lock< boost::fibers::mutex > lk( m);
  218. BOOST_CHECK(test2 == 0);
  219. test1 = 1;
  220. cv.notify_one();
  221. std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
  222. int count=0;
  223. while (test2 == 0 && cv.wait_for(lk, ms(250)) == boost::fibers::cv_status::no_timeout)
  224. count++;
  225. std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
  226. if (runs == 0) {
  227. BOOST_CHECK(t1 - t0 < ms(250));
  228. BOOST_CHECK(test2 != 0);
  229. } else {
  230. BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100+1000));
  231. BOOST_CHECK(test2 == 0);
  232. }
  233. ++runs;
  234. }
  235. void fn5( boost::fibers::mutex & m, boost::fibers::condition_variable & cv) {
  236. std::unique_lock< boost::fibers::mutex > lk( m);
  237. BOOST_CHECK(test2 == 0);
  238. test1 = 1;
  239. cv.notify_one();
  240. std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
  241. int count=0;
  242. cv.wait_for(lk, ms(250), Pred(test2));
  243. count++;
  244. std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
  245. if (runs == 0) {
  246. BOOST_CHECK(t1 - t0 < ms(250+1000));
  247. BOOST_CHECK(test2 != 0);
  248. } else {
  249. BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100));
  250. BOOST_CHECK(test2 == 0);
  251. }
  252. ++runs;
  253. }
  254. void do_test_condition_wait() {
  255. test1 = 0;
  256. test2 = 0;
  257. runs = 0;
  258. boost::fibers::mutex m;
  259. boost::fibers::condition_variable cv;
  260. std::unique_lock< boost::fibers::mutex > lk( m);
  261. boost::fibers::fiber f( boost::fibers::launch::post, & fn1, std::ref( m), std::ref( cv) );
  262. BOOST_CHECK(test1 == 0);
  263. while (test1 == 0)
  264. cv.wait(lk);
  265. BOOST_CHECK(test1 != 0);
  266. test2 = 1;
  267. lk.unlock();
  268. cv.notify_one();
  269. f.join();
  270. }
  271. void test_condition_wait() {
  272. boost::fibers::fiber( boost::fibers::launch::post, & do_test_condition_wait).join();
  273. do_test_condition_wait();
  274. }
  275. void do_test_condition_wait_until() {
  276. test1 = 0;
  277. test2 = 0;
  278. runs = 0;
  279. boost::fibers::mutex m;
  280. boost::fibers::condition_variable cv;
  281. {
  282. std::unique_lock< boost::fibers::mutex > lk( m);
  283. boost::fibers::fiber f( boost::fibers::launch::post, & fn2, std::ref( m), std::ref( cv) );
  284. BOOST_CHECK(test1 == 0);
  285. while (test1 == 0)
  286. cv.wait(lk);
  287. BOOST_CHECK(test1 != 0);
  288. test2 = 1;
  289. lk.unlock();
  290. cv.notify_one();
  291. f.join();
  292. }
  293. test1 = 0;
  294. test2 = 0;
  295. {
  296. std::unique_lock< boost::fibers::mutex > lk( m);
  297. boost::fibers::fiber f( boost::fibers::launch::post, & fn2, std::ref( m), std::ref( cv) );
  298. BOOST_CHECK(test1 == 0);
  299. while (test1 == 0)
  300. cv.wait(lk);
  301. BOOST_CHECK(test1 != 0);
  302. lk.unlock();
  303. f.join();
  304. }
  305. }
  306. void test_condition_wait_until() {
  307. boost::fibers::fiber( boost::fibers::launch::post, & do_test_condition_wait_until).join();
  308. do_test_condition_wait_until();
  309. }
  310. void do_test_condition_wait_until_pred() {
  311. test1 = 0;
  312. test2 = 0;
  313. runs = 0;
  314. boost::fibers::mutex m;
  315. boost::fibers::condition_variable cv;
  316. {
  317. std::unique_lock< boost::fibers::mutex > lk( m);
  318. boost::fibers::fiber f( boost::fibers::launch::post, & fn3, std::ref( m), std::ref( cv) );
  319. BOOST_CHECK(test1 == 0);
  320. while (test1 == 0)
  321. cv.wait(lk);
  322. BOOST_CHECK(test1 != 0);
  323. test2 = 1;
  324. lk.unlock();
  325. cv.notify_one();
  326. f.join();
  327. }
  328. test1 = 0;
  329. test2 = 0;
  330. {
  331. std::unique_lock< boost::fibers::mutex > lk( m);
  332. boost::fibers::fiber f( boost::fibers::launch::post, & fn3, std::ref( m), std::ref( cv) );
  333. BOOST_CHECK(test1 == 0);
  334. while (test1 == 0)
  335. cv.wait(lk);
  336. BOOST_CHECK(test1 != 0);
  337. lk.unlock();
  338. f.join();
  339. }
  340. }
  341. void test_condition_wait_until_pred() {
  342. boost::fibers::fiber( boost::fibers::launch::post, & do_test_condition_wait_until_pred).join();
  343. do_test_condition_wait_until_pred();
  344. }
  345. void do_test_condition_wait_for() {
  346. test1 = 0;
  347. test2 = 0;
  348. runs = 0;
  349. boost::fibers::mutex m;
  350. boost::fibers::condition_variable cv;
  351. {
  352. std::unique_lock< boost::fibers::mutex > lk( m);
  353. boost::fibers::fiber f( boost::fibers::launch::post, & fn4, std::ref( m), std::ref( cv) );
  354. BOOST_CHECK(test1 == 0);
  355. while (test1 == 0)
  356. cv.wait(lk);
  357. BOOST_CHECK(test1 != 0);
  358. test2 = 1;
  359. lk.unlock();
  360. cv.notify_one();
  361. f.join();
  362. }
  363. test1 = 0;
  364. test2 = 0;
  365. {
  366. std::unique_lock< boost::fibers::mutex > lk( m);
  367. boost::fibers::fiber f( boost::fibers::launch::post, & fn4, std::ref( m), std::ref( cv) );
  368. BOOST_CHECK(test1 == 0);
  369. while (test1 == 0)
  370. cv.wait(lk);
  371. BOOST_CHECK(test1 != 0);
  372. lk.unlock();
  373. f.join();
  374. }
  375. }
  376. void test_condition_wait_for() {
  377. boost::fibers::fiber( boost::fibers::launch::post, & do_test_condition_wait_for).join();
  378. do_test_condition_wait_for();
  379. }
  380. void do_test_condition_wait_for_pred() {
  381. test1 = 0;
  382. test2 = 0;
  383. runs = 0;
  384. boost::fibers::mutex m;
  385. boost::fibers::condition_variable cv;
  386. {
  387. std::unique_lock< boost::fibers::mutex > lk( m);
  388. boost::fibers::fiber f( boost::fibers::launch::post, & fn5, std::ref( m), std::ref( cv) );
  389. BOOST_CHECK(test1 == 0);
  390. while (test1 == 0)
  391. cv.wait(lk);
  392. BOOST_CHECK(test1 != 0);
  393. test2 = 1;
  394. lk.unlock();
  395. cv.notify_one();
  396. f.join();
  397. }
  398. test1 = 0;
  399. test2 = 0;
  400. {
  401. std::unique_lock< boost::fibers::mutex > lk( m);
  402. boost::fibers::fiber f( boost::fibers::launch::post, & fn5, std::ref( m), std::ref( cv) );
  403. BOOST_CHECK(test1 == 0);
  404. while (test1 == 0)
  405. cv.wait(lk);
  406. BOOST_CHECK(test1 != 0);
  407. lk.unlock();
  408. f.join();
  409. }
  410. }
  411. void test_condition_wait_for_pred() {
  412. boost::fibers::fiber( boost::fibers::launch::post, & do_test_condition_wait_for_pred).join();
  413. do_test_condition_wait_for_pred();
  414. }
  415. boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
  416. {
  417. boost::unit_test::test_suite * test =
  418. BOOST_TEST_SUITE("Boost.Fiber: condition_variable test suite");
  419. test->add( BOOST_TEST_CASE( & test_one_waiter_notify_one) );
  420. test->add( BOOST_TEST_CASE( & test_two_waiter_notify_one) );
  421. test->add( BOOST_TEST_CASE( & test_two_waiter_notify_all) );
  422. test->add( BOOST_TEST_CASE( & test_condition_wait) );
  423. test->add( BOOST_TEST_CASE( & test_condition_wait_until) );
  424. test->add( BOOST_TEST_CASE( & test_condition_wait_until_pred) );
  425. test->add( BOOST_TEST_CASE( & test_condition_wait_for) );
  426. test->add( BOOST_TEST_CASE( & test_condition_wait_for_pred) );
  427. return test;
  428. }