test_lock_concept.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  1. // (C) Copyright 2006-8 Anthony Williams
  2. // Distributed under the Boost Software License, Version 1.0. (See
  3. // accompanying file LICENSE_1_0.txt or copy at
  4. // http://www.boost.org/LICENSE_1_0.txt)
  5. #define BOOST_THREAD_VERSION 2
  6. #define BOOST_TEST_MODULE Boost.Threads: lock_concept test suite
  7. #include <boost/test/unit_test.hpp>
  8. #include <boost/test/test_case_template.hpp>
  9. #include <boost/mpl/vector.hpp>
  10. #include <boost/thread/mutex.hpp>
  11. #include <boost/thread/lock_types.hpp>
  12. #include <boost/thread/shared_mutex.hpp>
  13. #include <boost/thread/thread_only.hpp>
  14. #include <boost/thread/recursive_mutex.hpp>
  15. #include <boost/thread/condition_variable.hpp>
  16. template<typename Mutex,typename Lock>
  17. struct test_initially_locked
  18. {
  19. void operator()() const
  20. {
  21. Mutex m;
  22. Lock lock(m);
  23. BOOST_CHECK(lock);
  24. BOOST_CHECK(lock.owns_lock());
  25. }
  26. };
  27. template<typename Mutex,typename Lock>
  28. struct test_initially_unlocked_if_other_thread_has_lock
  29. {
  30. Mutex m;
  31. boost::mutex done_mutex;
  32. bool done;
  33. bool locked;
  34. boost::condition_variable done_cond;
  35. test_initially_unlocked_if_other_thread_has_lock():
  36. done(false),locked(false)
  37. {}
  38. void locking_thread()
  39. {
  40. Lock lock(m);
  41. boost::lock_guard<boost::mutex> lk(done_mutex);
  42. locked=lock.owns_lock();
  43. done=true;
  44. done_cond.notify_one();
  45. }
  46. bool is_done() const
  47. {
  48. return done;
  49. }
  50. void operator()()
  51. {
  52. Lock lock(m);
  53. typedef test_initially_unlocked_if_other_thread_has_lock<Mutex,Lock> this_type;
  54. boost::thread t(&this_type::locking_thread,this);
  55. try
  56. {
  57. {
  58. boost::unique_lock<boost::mutex> lk(done_mutex);
  59. BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
  60. boost::bind(&this_type::is_done,this)));
  61. BOOST_CHECK(!locked);
  62. }
  63. lock.unlock();
  64. t.join();
  65. }
  66. catch(...)
  67. {
  68. lock.unlock();
  69. t.join();
  70. throw;
  71. }
  72. }
  73. };
  74. template<typename Mutex,typename Lock>
  75. struct test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock
  76. {
  77. Mutex m;
  78. boost::mutex done_mutex;
  79. bool done;
  80. bool locked;
  81. boost::condition_variable done_cond;
  82. test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock():
  83. done(false),locked(false)
  84. {}
  85. void locking_thread()
  86. {
  87. Lock lock(m,boost::try_to_lock);
  88. boost::lock_guard<boost::mutex> lk(done_mutex);
  89. locked=lock.owns_lock();
  90. done=true;
  91. done_cond.notify_one();
  92. }
  93. bool is_done() const
  94. {
  95. return done;
  96. }
  97. void operator()()
  98. {
  99. boost::unique_lock<Mutex> lock(m);
  100. typedef test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock<Mutex,Lock> this_type;
  101. boost::thread t(&this_type::locking_thread,this);
  102. try
  103. {
  104. {
  105. boost::unique_lock<boost::mutex> lk(done_mutex);
  106. BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
  107. boost::bind(&this_type::is_done,this)));
  108. BOOST_CHECK(!locked);
  109. }
  110. lock.unlock();
  111. t.join();
  112. }
  113. catch(...)
  114. {
  115. lock.unlock();
  116. t.join();
  117. throw;
  118. }
  119. }
  120. };
  121. template<typename Mutex,typename Lock>
  122. struct test_initially_locked_if_other_thread_has_shared_lock
  123. {
  124. Mutex m;
  125. boost::mutex done_mutex;
  126. bool done;
  127. bool locked;
  128. boost::condition_variable done_cond;
  129. test_initially_locked_if_other_thread_has_shared_lock():
  130. done(false),locked(false)
  131. {}
  132. void locking_thread()
  133. {
  134. Lock lock(m);
  135. boost::lock_guard<boost::mutex> lk(done_mutex);
  136. locked=lock.owns_lock();
  137. done=true;
  138. done_cond.notify_one();
  139. }
  140. bool is_done() const
  141. {
  142. return done;
  143. }
  144. void operator()()
  145. {
  146. boost::shared_lock<Mutex> lock(m);
  147. typedef test_initially_locked_if_other_thread_has_shared_lock<Mutex,Lock> this_type;
  148. boost::thread t(&this_type::locking_thread,this);
  149. try
  150. {
  151. {
  152. boost::unique_lock<boost::mutex> lk(done_mutex);
  153. BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
  154. boost::bind(&this_type::is_done,this)));
  155. BOOST_CHECK(locked);
  156. }
  157. lock.unlock();
  158. t.join();
  159. }
  160. catch(...)
  161. {
  162. lock.unlock();
  163. t.join();
  164. throw;
  165. }
  166. }
  167. };
  168. template<typename Mutex,typename Lock>
  169. struct test_initially_unlocked_with_defer_lock_parameter
  170. {
  171. void operator()() const
  172. {
  173. Mutex m;
  174. Lock lock(m,boost::defer_lock);
  175. BOOST_CHECK(!lock);
  176. BOOST_CHECK(!lock.owns_lock());
  177. }
  178. };
  179. template<typename Mutex,typename Lock>
  180. struct test_initially_locked_with_adopt_lock_parameter
  181. {
  182. void operator()() const
  183. {
  184. Mutex m;
  185. m.lock();
  186. Lock lock(m,boost::adopt_lock);
  187. BOOST_CHECK(lock);
  188. BOOST_CHECK(lock.owns_lock());
  189. }
  190. };
  191. template<typename Mutex,typename Lock>
  192. struct test_initially_lock_shared_with_adopt_lock_parameter
  193. {
  194. void operator()() const
  195. {
  196. Mutex m;
  197. m.lock_shared();
  198. Lock lock(m,boost::adopt_lock);
  199. BOOST_CHECK(lock);
  200. BOOST_CHECK(lock.owns_lock());
  201. }
  202. };
  203. template<typename Mutex,typename Lock>
  204. struct test_unlocked_after_unlock_called
  205. {
  206. void operator()() const
  207. {
  208. Mutex m;
  209. Lock lock(m);
  210. lock.unlock();
  211. BOOST_CHECK(!lock);
  212. BOOST_CHECK(!lock.owns_lock());
  213. }
  214. };
  215. template<typename Mutex,typename Lock>
  216. struct test_locked_after_lock_called
  217. {
  218. void operator()() const
  219. {
  220. Mutex m;
  221. Lock lock(m,boost::defer_lock);
  222. lock.lock();
  223. BOOST_CHECK(lock);
  224. BOOST_CHECK(lock.owns_lock());
  225. }
  226. };
  227. template<typename Mutex,typename Lock>
  228. struct test_locked_after_try_lock_called
  229. {
  230. void operator()() const
  231. {
  232. Mutex m;
  233. Lock lock(m,boost::defer_lock);
  234. lock.try_lock();
  235. BOOST_CHECK(lock);
  236. BOOST_CHECK(lock.owns_lock());
  237. }
  238. };
  239. template<typename Mutex,typename Lock>
  240. struct test_unlocked_after_try_lock_if_other_thread_has_lock
  241. {
  242. Mutex m;
  243. boost::mutex done_mutex;
  244. bool done;
  245. bool locked;
  246. boost::condition_variable done_cond;
  247. test_unlocked_after_try_lock_if_other_thread_has_lock():
  248. done(false),locked(false)
  249. {}
  250. void locking_thread()
  251. {
  252. Lock lock(m,boost::defer_lock);
  253. boost::lock_guard<boost::mutex> lk(done_mutex);
  254. locked=lock.owns_lock();
  255. done=true;
  256. done_cond.notify_one();
  257. }
  258. bool is_done() const
  259. {
  260. return done;
  261. }
  262. void operator()()
  263. {
  264. Lock lock(m);
  265. typedef test_unlocked_after_try_lock_if_other_thread_has_lock<Mutex,Lock> this_type;
  266. boost::thread t(&this_type::locking_thread,this);
  267. try
  268. {
  269. {
  270. boost::unique_lock<boost::mutex> lk(done_mutex);
  271. BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
  272. boost::bind(&this_type::is_done,this)));
  273. BOOST_CHECK(!locked);
  274. }
  275. lock.unlock();
  276. t.join();
  277. }
  278. catch(...)
  279. {
  280. lock.unlock();
  281. t.join();
  282. throw;
  283. }
  284. }
  285. };
  286. template<typename Mutex,typename Lock>
  287. struct test_throws_if_lock_called_when_already_locked
  288. {
  289. void operator()() const
  290. {
  291. Mutex m;
  292. Lock lock(m);
  293. BOOST_CHECK_THROW( lock.lock(), boost::lock_error );
  294. }
  295. };
  296. template<typename Mutex,typename Lock>
  297. struct test_throws_if_try_lock_called_when_already_locked
  298. {
  299. void operator()() const
  300. {
  301. Mutex m;
  302. Lock lock(m);
  303. BOOST_CHECK_THROW( lock.try_lock(), boost::lock_error );
  304. }
  305. };
  306. template<typename Mutex,typename Lock>
  307. struct test_throws_if_unlock_called_when_already_unlocked
  308. {
  309. void operator()() const
  310. {
  311. Mutex m;
  312. Lock lock(m);
  313. lock.unlock();
  314. BOOST_CHECK_THROW( lock.unlock(), boost::lock_error );
  315. }
  316. };
  317. template<typename Lock>
  318. struct test_default_constructed_has_no_mutex_and_unlocked
  319. {
  320. void operator()() const
  321. {
  322. Lock l;
  323. BOOST_CHECK(!l.mutex());
  324. BOOST_CHECK(!l.owns_lock());
  325. }
  326. };
  327. template<typename Mutex,typename Lock>
  328. struct test_locks_can_be_swapped
  329. {
  330. void operator()() const
  331. {
  332. Mutex m1;
  333. Mutex m2;
  334. Mutex m3;
  335. Lock l1(m1);
  336. Lock l2(m2);
  337. BOOST_CHECK_EQUAL(l1.mutex(),&m1);
  338. BOOST_CHECK_EQUAL(l2.mutex(),&m2);
  339. l1.swap(l2);
  340. BOOST_CHECK_EQUAL(l1.mutex(),&m2);
  341. BOOST_CHECK_EQUAL(l2.mutex(),&m1);
  342. swap(l1,l2);
  343. BOOST_CHECK_EQUAL(l1.mutex(),&m1);
  344. BOOST_CHECK_EQUAL(l2.mutex(),&m2);
  345. #if 0
  346. l1.swap(Lock(m3));
  347. BOOST_CHECK_EQUAL(l1.mutex(),&m3);
  348. #endif
  349. }
  350. };
  351. template<typename Mutex,typename Lock>
  352. void test_lock_is_scoped_lock_concept_for_mutex()
  353. {
  354. test_default_constructed_has_no_mutex_and_unlocked<Lock>()();
  355. test_initially_locked<Mutex,Lock>()();
  356. test_initially_unlocked_with_defer_lock_parameter<Mutex,Lock>()();
  357. test_initially_locked_with_adopt_lock_parameter<Mutex,Lock>()();
  358. test_unlocked_after_unlock_called<Mutex,Lock>()();
  359. test_locked_after_lock_called<Mutex,Lock>()();
  360. test_throws_if_lock_called_when_already_locked<Mutex,Lock>()();
  361. test_throws_if_unlock_called_when_already_unlocked<Mutex,Lock>()();
  362. test_locks_can_be_swapped<Mutex,Lock>()();
  363. test_locked_after_try_lock_called<Mutex,Lock>()();
  364. test_throws_if_try_lock_called_when_already_locked<Mutex,Lock>()();
  365. test_unlocked_after_try_lock_if_other_thread_has_lock<Mutex,Lock>()();
  366. }
  367. typedef boost::mpl::vector<boost::mutex,boost::timed_mutex,
  368. boost::recursive_mutex,boost::recursive_timed_mutex> mutex_types_with_scoped_lock;
  369. BOOST_AUTO_TEST_CASE_TEMPLATE(test_scoped_lock_concept,Mutex,mutex_types_with_scoped_lock)
  370. {
  371. typedef typename Mutex::scoped_lock Lock;
  372. test_lock_is_scoped_lock_concept_for_mutex<Mutex,Lock>();
  373. }
  374. typedef boost::mpl::vector<boost::mutex,boost::timed_mutex,
  375. boost::recursive_mutex,boost::recursive_timed_mutex,boost::shared_mutex> all_mutex_types;
  376. BOOST_AUTO_TEST_CASE_TEMPLATE(test_unique_lock_is_scoped_lock,Mutex,all_mutex_types)
  377. {
  378. typedef boost::unique_lock<Mutex> Lock;
  379. test_lock_is_scoped_lock_concept_for_mutex<Mutex,Lock>();
  380. }
  381. typedef boost::mpl::vector<boost::try_mutex,boost::timed_mutex,
  382. boost::recursive_try_mutex,boost::recursive_timed_mutex> mutex_types_with_scoped_try_lock;
  383. BOOST_AUTO_TEST_CASE_TEMPLATE(test_scoped_try_lock_concept,Mutex,mutex_types_with_scoped_try_lock)
  384. {
  385. typedef typename Mutex::scoped_try_lock Lock;
  386. test_default_constructed_has_no_mutex_and_unlocked<Lock>()();
  387. test_initially_locked<Mutex,Lock>()();
  388. test_initially_unlocked_if_other_thread_has_lock<Mutex,Lock>()();
  389. test_initially_unlocked_with_defer_lock_parameter<Mutex,Lock>()();
  390. test_initially_locked_with_adopt_lock_parameter<Mutex,Lock>()();
  391. test_unlocked_after_unlock_called<Mutex,Lock>()();
  392. test_locked_after_lock_called<Mutex,Lock>()();
  393. test_locked_after_try_lock_called<Mutex,Lock>()();
  394. test_unlocked_after_try_lock_if_other_thread_has_lock<Mutex,Lock>()();
  395. test_throws_if_lock_called_when_already_locked<Mutex,Lock>()();
  396. test_throws_if_try_lock_called_when_already_locked<Mutex,Lock>()();
  397. test_throws_if_unlock_called_when_already_unlocked<Mutex,Lock>()();
  398. test_locks_can_be_swapped<Mutex,Lock>()();
  399. }
  400. struct dummy_shared_mutex
  401. {
  402. bool locked;
  403. bool shared_locked;
  404. bool shared_unlocked;
  405. bool shared_timed_locked_relative;
  406. bool shared_timed_locked_absolute;
  407. bool timed_locked_relative;
  408. bool timed_locked_absolute;
  409. dummy_shared_mutex():
  410. locked(false),shared_locked(false),shared_unlocked(false),
  411. shared_timed_locked_relative(false),
  412. shared_timed_locked_absolute(false),
  413. timed_locked_relative(false),
  414. timed_locked_absolute(false)
  415. {}
  416. void lock()
  417. {
  418. locked=true;
  419. }
  420. void lock_shared()
  421. {
  422. shared_locked=true;
  423. }
  424. void unlock()
  425. {}
  426. void unlock_shared()
  427. {
  428. shared_unlocked=true;
  429. }
  430. bool timed_lock_shared(boost::system_time)
  431. {
  432. shared_timed_locked_absolute=true;
  433. return false;
  434. }
  435. template<typename Duration>
  436. bool timed_lock_shared(Duration)
  437. {
  438. shared_timed_locked_relative=true;
  439. return false;
  440. }
  441. bool timed_lock(boost::system_time)
  442. {
  443. timed_locked_absolute=true;
  444. return false;
  445. }
  446. template<typename Duration>
  447. bool timed_lock(Duration)
  448. {
  449. timed_locked_relative=true;
  450. return false;
  451. }
  452. };
  453. BOOST_AUTO_TEST_CASE(test_shared_lock)
  454. {
  455. typedef boost::shared_mutex Mutex;
  456. typedef boost::shared_lock<Mutex> Lock;
  457. test_default_constructed_has_no_mutex_and_unlocked<Lock>()();
  458. test_initially_locked<Mutex,Lock>()();
  459. test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock<Mutex,Lock>()();
  460. test_initially_locked_if_other_thread_has_shared_lock<Mutex,Lock>()();
  461. test_initially_unlocked_with_defer_lock_parameter<Mutex,Lock>()();
  462. test_initially_lock_shared_with_adopt_lock_parameter<Mutex,Lock>()();
  463. test_unlocked_after_unlock_called<Mutex,Lock>()();
  464. test_locked_after_lock_called<Mutex,Lock>()();
  465. test_locked_after_try_lock_called<Mutex,Lock>()();
  466. test_throws_if_lock_called_when_already_locked<Mutex,Lock>()();
  467. test_throws_if_try_lock_called_when_already_locked<Mutex,Lock>()();
  468. test_throws_if_unlock_called_when_already_unlocked<Mutex,Lock>()();
  469. test_locks_can_be_swapped<Mutex,Lock>()();
  470. dummy_shared_mutex dummy;
  471. boost::shared_lock<dummy_shared_mutex> lk(dummy);
  472. BOOST_CHECK(dummy.shared_locked);
  473. lk.unlock();
  474. BOOST_CHECK(dummy.shared_unlocked);
  475. lk.timed_lock(boost::posix_time::milliseconds(5));
  476. BOOST_CHECK(dummy.shared_timed_locked_relative);
  477. lk.timed_lock(boost::get_system_time());
  478. BOOST_CHECK(dummy.shared_timed_locked_absolute);
  479. }
  480. //boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
  481. //{
  482. // boost::unit_test::test_suite* test =
  483. // BOOST_TEST_SUITE("Boost.Threads: lock concept test suite");
  484. //
  485. // typedef boost::mpl::vector<boost::mutex,boost::try_mutex,boost::timed_mutex,
  486. // boost::recursive_mutex,boost::recursive_try_mutex,boost::recursive_timed_mutex> mutex_types_with_scoped_lock;
  487. //
  488. // test->add(BOOST_TEST_CASE_TEMPLATE(test_scoped_lock_concept,mutex_types_with_scoped_lock));
  489. //
  490. // typedef boost::mpl::vector<boost::try_mutex,boost::timed_mutex,
  491. // boost::recursive_try_mutex,boost::recursive_timed_mutex> mutex_types_with_scoped_try_lock;
  492. //
  493. // test->add(BOOST_TEST_CASE_TEMPLATE(test_scoped_try_lock_concept,mutex_types_with_scoped_try_lock));
  494. //
  495. // typedef boost::mpl::vector<boost::mutex,boost::try_mutex,boost::timed_mutex,
  496. // boost::recursive_mutex,boost::recursive_try_mutex,boost::recursive_timed_mutex,boost::shared_mutex> all_mutex_types;
  497. //
  498. // test->add(BOOST_TEST_CASE_TEMPLATE(test_unique_lock_is_scoped_lock,all_mutex_types));
  499. // test->add(BOOST_TEST_CASE(&test_shared_lock));
  500. //
  501. // return test;
  502. //}