test_mutex_post.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  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 <cstdlib>
  9. #include <iostream>
  10. #include <map>
  11. #include <mutex>
  12. #include <stdexcept>
  13. #include <vector>
  14. #include <boost/test/unit_test.hpp>
  15. #include <boost/fiber/all.hpp>
  16. typedef std::chrono::nanoseconds ns;
  17. typedef std::chrono::milliseconds ms;
  18. int value1 = 0;
  19. int value2 = 0;
  20. template< typename M >
  21. void fn1( M & mtx) {
  22. typedef M mutex_type;
  23. typename std::unique_lock< mutex_type > lk( mtx);
  24. ++value1;
  25. for ( int i = 0; i < 3; ++i)
  26. boost::this_fiber::yield();
  27. }
  28. template< typename M >
  29. void fn2( M & mtx) {
  30. typedef M mutex_type;
  31. ++value2;
  32. typename std::unique_lock< mutex_type > lk( mtx);
  33. ++value2;
  34. }
  35. void fn3( boost::fibers::timed_mutex & m) {
  36. std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
  37. m.lock();
  38. std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
  39. m.unlock();
  40. ns d = t1 - t0 - ms(250);
  41. BOOST_CHECK(d < ns(2500000)+ms(2000)); // within 2.5 ms
  42. }
  43. void fn4( boost::fibers::timed_mutex & m) {
  44. std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
  45. while ( ! m.try_lock() );
  46. std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
  47. m.unlock();
  48. ns d = t1 - t0 - ms(250);
  49. BOOST_CHECK(d < ns(50000000)+ms(2000)); // within 50 ms
  50. }
  51. void fn5( boost::fibers::timed_mutex & m) {
  52. std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
  53. BOOST_CHECK( m.try_lock_for(ms(300)+ms(2000)) == true);
  54. std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
  55. m.unlock();
  56. ns d = t1 - t0 - ms(250);
  57. BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms
  58. }
  59. void fn6( boost::fibers::timed_mutex & m) {
  60. std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
  61. BOOST_CHECK(m.try_lock_for(ms(250)) == false);
  62. std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
  63. ns d = t1 - t0 - ms(250);
  64. BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms
  65. }
  66. void fn7( boost::fibers::timed_mutex & m) {
  67. std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
  68. BOOST_CHECK(m.try_lock_until(std::chrono::steady_clock::now() + ms(300) + ms(1000)) == true);
  69. std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
  70. m.unlock();
  71. ns d = t1 - t0 - ms(250);
  72. BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5ms
  73. }
  74. void fn8( boost::fibers::timed_mutex & m) {
  75. std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
  76. BOOST_CHECK(m.try_lock_until(std::chrono::steady_clock::now() + ms(250)) == false);
  77. std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
  78. ns d = t1 - t0 - ms(250);
  79. ns r = ns(5000000)+ms(2000); // within 6ms
  80. BOOST_CHECK(d < r); // within 6ms
  81. }
  82. void fn9( boost::fibers::recursive_timed_mutex & m) {
  83. std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
  84. m.lock();
  85. std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
  86. m.lock();
  87. m.unlock();
  88. m.unlock();
  89. ns d = t1 - t0 - ms(250);
  90. BOOST_CHECK(d < ms(2500)+ms(2000)); // within 2.5 ms
  91. }
  92. void fn10( boost::fibers::recursive_timed_mutex & m) {
  93. std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
  94. while (!m.try_lock()) ;
  95. std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
  96. BOOST_CHECK(m.try_lock());
  97. m.unlock();
  98. m.unlock();
  99. ns d = t1 - t0 - ms(250);
  100. BOOST_CHECK(d < ns(50000000)+ms(2000)); // within 50 ms
  101. }
  102. void fn11( boost::fibers::recursive_timed_mutex & m) {
  103. std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
  104. BOOST_CHECK(m.try_lock_for(ms(300)+ms(1000)) == true);
  105. std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
  106. BOOST_CHECK(m.try_lock());
  107. m.unlock();
  108. m.unlock();
  109. ns d = t1 - t0 - ms(250);
  110. BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms
  111. }
  112. void fn12( boost::fibers::recursive_timed_mutex & m) {
  113. std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
  114. BOOST_CHECK(m.try_lock_for(ms(250)) == false);
  115. std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
  116. ns d = t1 - t0 - ms(250);
  117. BOOST_CHECK(d < ms(5000)+ms(2000)); // within 5 ms
  118. }
  119. void fn13( boost::fibers::recursive_timed_mutex & m) {
  120. std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
  121. BOOST_CHECK(m.try_lock_until(std::chrono::steady_clock::now() + ms(300) + ms(1000)) == true);
  122. std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
  123. m.unlock();
  124. ns d = t1 - t0 - ms(250);
  125. BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms
  126. }
  127. void fn14( boost::fibers::recursive_timed_mutex & m) {
  128. std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
  129. BOOST_CHECK(m.try_lock_until(std::chrono::steady_clock::now() + ms(250)) == false);
  130. std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
  131. ns d = t1 - t0 - ms(250);
  132. BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms
  133. }
  134. void fn15( boost::fibers::recursive_mutex & m) {
  135. std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
  136. m.lock();
  137. std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
  138. m.lock();
  139. m.unlock();
  140. m.unlock();
  141. ns d = t1 - t0 - ms(250);
  142. BOOST_CHECK(d < ns(2500000)+ms(2000)); // within 2.5 ms
  143. }
  144. void fn16( boost::fibers::recursive_mutex & m) {
  145. std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
  146. while (!m.try_lock());
  147. std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
  148. BOOST_CHECK(m.try_lock());
  149. m.unlock();
  150. m.unlock();
  151. ns d = t1 - t0 - ms(250);
  152. BOOST_CHECK(d < ns(50000000)+ms(2000)); // within 50 ms
  153. }
  154. void fn17( boost::fibers::mutex & m) {
  155. std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
  156. m.lock();
  157. std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
  158. m.unlock();
  159. ns d = t1 - t0 - ms(250);
  160. BOOST_CHECK(d < ns(2500000)+ms(2000)); // within 2.5 ms
  161. }
  162. void fn18( boost::fibers::mutex & m) {
  163. std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
  164. while (!m.try_lock()) ;
  165. std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
  166. m.unlock();
  167. ns d = t1 - t0 - ms(250);
  168. BOOST_CHECK(d < ns(50000000)+ms(2000)); // within 50 ms
  169. }
  170. template< typename M >
  171. struct test_lock {
  172. typedef M mutex_type;
  173. typedef typename std::unique_lock< M > lock_type;
  174. void operator()() {
  175. mutex_type mtx;
  176. // Test the lock's constructors.
  177. {
  178. lock_type lk(mtx, std::defer_lock);
  179. BOOST_CHECK(!lk);
  180. }
  181. lock_type lk(mtx);
  182. BOOST_CHECK(lk ? true : false);
  183. // Test the lock and unlock methods.
  184. lk.unlock();
  185. BOOST_CHECK(!lk);
  186. lk.lock();
  187. BOOST_CHECK(lk ? true : false);
  188. }
  189. };
  190. template< typename M >
  191. struct test_exclusive {
  192. typedef M mutex_type;
  193. typedef typename std::unique_lock< M > lock_type;
  194. void operator()() {
  195. value1 = 0;
  196. value2 = 0;
  197. BOOST_CHECK_EQUAL( 0, value1);
  198. BOOST_CHECK_EQUAL( 0, value2);
  199. mutex_type mtx;
  200. boost::fibers::fiber f1( boost::fibers::launch::post, & fn1< mutex_type >, std::ref( mtx) );
  201. boost::fibers::fiber f2( boost::fibers::launch::post, & fn2< mutex_type >, std::ref( mtx) );
  202. BOOST_ASSERT( f1.joinable() );
  203. BOOST_ASSERT( f2.joinable() );
  204. f1.join();
  205. f2.join();
  206. BOOST_CHECK_EQUAL( 1, value1);
  207. BOOST_CHECK_EQUAL( 2, value2);
  208. }
  209. };
  210. template< typename M >
  211. struct test_recursive_lock {
  212. typedef M mutex_type;
  213. typedef typename std::unique_lock< M > lock_type;
  214. void operator()() {
  215. mutex_type mx;
  216. lock_type lock1(mx);
  217. lock_type lock2(mx);
  218. }
  219. };
  220. void do_test_mutex() {
  221. test_lock< boost::fibers::mutex >()();
  222. test_exclusive< boost::fibers::mutex >()();
  223. {
  224. boost::fibers::mutex mtx;
  225. mtx.lock();
  226. boost::fibers::fiber f( boost::fibers::launch::post, & fn17, std::ref( mtx) );
  227. boost::this_fiber::sleep_for( ms(250) );
  228. mtx.unlock();
  229. f.join();
  230. }
  231. {
  232. boost::fibers::mutex mtx;
  233. mtx.lock();
  234. boost::fibers::fiber f( boost::fibers::launch::post, & fn18, std::ref( mtx) );
  235. boost::this_fiber::sleep_for( ms(250) );
  236. mtx.unlock();
  237. f.join();
  238. }
  239. }
  240. void test_mutex() {
  241. boost::fibers::fiber( boost::fibers::launch::post, & do_test_mutex).join();
  242. }
  243. void do_test_recursive_mutex() {
  244. test_lock< boost::fibers::recursive_mutex >()();
  245. test_exclusive< boost::fibers::recursive_mutex >()();
  246. test_recursive_lock< boost::fibers::recursive_mutex >()();
  247. {
  248. boost::fibers::recursive_mutex mtx;
  249. mtx.lock();
  250. boost::fibers::fiber f( boost::fibers::launch::post, & fn15, std::ref( mtx) );
  251. boost::this_fiber::sleep_for( ms(250) );
  252. mtx.unlock();
  253. f.join();
  254. }
  255. {
  256. boost::fibers::recursive_mutex mtx;
  257. mtx.lock();
  258. boost::fibers::fiber f( boost::fibers::launch::post, & fn16, std::ref( mtx) );
  259. boost::this_fiber::sleep_for( ms(250) );
  260. mtx.unlock();
  261. f.join();
  262. }
  263. }
  264. void test_recursive_mutex() {
  265. boost::fibers::fiber( boost::fibers::launch::post, do_test_recursive_mutex).join();
  266. }
  267. void do_test_timed_mutex() {
  268. test_lock< boost::fibers::timed_mutex >()();
  269. test_exclusive< boost::fibers::timed_mutex >()();
  270. {
  271. boost::fibers::timed_mutex timed_mtx;
  272. timed_mtx.lock();
  273. boost::fibers::fiber f( boost::fibers::launch::post, & fn3, std::ref( timed_mtx) );
  274. boost::this_fiber::sleep_for( ms(250) );
  275. timed_mtx.unlock();
  276. f.join();
  277. }
  278. {
  279. boost::fibers::timed_mutex timed_mtx;
  280. timed_mtx.lock();
  281. boost::fibers::fiber f( boost::fibers::launch::post, & fn4, std::ref( timed_mtx) );
  282. boost::this_fiber::sleep_for( ms(250) );
  283. timed_mtx.unlock();
  284. f.join();
  285. }
  286. {
  287. boost::fibers::timed_mutex timed_mtx;
  288. timed_mtx.lock();
  289. boost::fibers::fiber f( boost::fibers::launch::post, & fn5, std::ref( timed_mtx) );
  290. boost::this_fiber::sleep_for( ms(250) );
  291. timed_mtx.unlock();
  292. f.join();
  293. }
  294. {
  295. boost::fibers::timed_mutex timed_mtx;
  296. timed_mtx.lock();
  297. boost::fibers::fiber f( boost::fibers::launch::post, & fn6, std::ref( timed_mtx) );
  298. boost::this_fiber::sleep_for( ms(300) );
  299. timed_mtx.unlock();
  300. f.join();
  301. }
  302. {
  303. boost::fibers::timed_mutex timed_mtx;
  304. timed_mtx.lock();
  305. boost::fibers::fiber f( boost::fibers::launch::post, & fn7, std::ref( timed_mtx) );
  306. boost::this_fiber::sleep_for( ms(250) );
  307. timed_mtx.unlock();
  308. f.join();
  309. }
  310. {
  311. boost::fibers::timed_mutex timed_mtx;
  312. timed_mtx.lock();
  313. boost::fibers::fiber f( boost::fibers::launch::post, & fn8, std::ref( timed_mtx) );
  314. boost::this_fiber::sleep_for( ms(300) + ms(1000) );
  315. timed_mtx.unlock();
  316. f.join();
  317. }
  318. }
  319. void test_timed_mutex() {
  320. boost::fibers::fiber( boost::fibers::launch::post, & do_test_timed_mutex).join();
  321. }
  322. void do_test_recursive_timed_mutex() {
  323. test_lock< boost::fibers::recursive_timed_mutex >()();
  324. test_exclusive< boost::fibers::recursive_timed_mutex >()();
  325. test_recursive_lock< boost::fibers::recursive_timed_mutex >()();
  326. {
  327. boost::fibers::recursive_timed_mutex timed_mtx;
  328. timed_mtx.lock();
  329. boost::fibers::fiber f( boost::fibers::launch::post, & fn9, std::ref( timed_mtx) );
  330. boost::this_fiber::sleep_for( ms(250) );
  331. timed_mtx.unlock();
  332. f.join();
  333. }
  334. {
  335. boost::fibers::recursive_timed_mutex timed_mtx;
  336. timed_mtx.lock();
  337. boost::fibers::fiber f( boost::fibers::launch::post, & fn10, std::ref( timed_mtx) );
  338. boost::this_fiber::sleep_for( ms(250) );
  339. timed_mtx.unlock();
  340. f.join();
  341. }
  342. {
  343. boost::fibers::recursive_timed_mutex timed_mtx;
  344. timed_mtx.lock();
  345. boost::fibers::fiber f( boost::fibers::launch::post, & fn11, std::ref( timed_mtx) );
  346. boost::this_fiber::sleep_for( ms(250) );
  347. timed_mtx.unlock();
  348. f.join();
  349. }
  350. {
  351. boost::fibers::recursive_timed_mutex timed_mtx;
  352. timed_mtx.lock();
  353. boost::fibers::fiber f( boost::fibers::launch::post, & fn12, std::ref( timed_mtx) );
  354. boost::this_fiber::sleep_for( ms(400) );
  355. timed_mtx.unlock();
  356. f.join();
  357. }
  358. {
  359. boost::fibers::recursive_timed_mutex timed_mtx;
  360. timed_mtx.lock();
  361. boost::fibers::fiber f( boost::fibers::launch::post, & fn13, std::ref( timed_mtx) );
  362. boost::this_fiber::sleep_for( ms(250) );
  363. timed_mtx.unlock();
  364. f.join();
  365. }
  366. {
  367. boost::fibers::recursive_timed_mutex timed_mtx;
  368. timed_mtx.lock();
  369. boost::fibers::fiber f( boost::fibers::launch::post, & fn14, std::ref( timed_mtx) );
  370. boost::this_fiber::sleep_for( ms(300) );
  371. timed_mtx.unlock();
  372. f.join();
  373. }
  374. }
  375. void test_recursive_timed_mutex() {
  376. boost::fibers::fiber( boost::fibers::launch::post, & do_test_recursive_timed_mutex).join();
  377. }
  378. boost::unit_test::test_suite * init_unit_test_suite( int, char* []) {
  379. boost::unit_test::test_suite * test =
  380. BOOST_TEST_SUITE("Boost.Fiber: mutex test suite");
  381. test->add( BOOST_TEST_CASE( & test_mutex) );
  382. test->add( BOOST_TEST_CASE( & test_recursive_mutex) );
  383. test->add( BOOST_TEST_CASE( & test_timed_mutex) );
  384. test->add( BOOST_TEST_CASE( & test_recursive_timed_mutex) );
  385. return test;
  386. }