mutex_test.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. // Copyright (C) 2001-2003
  2. // William E. Kempf
  3. //
  4. // Copyright Frank Mori Hess 2009
  5. //
  6. // Use, modification and
  7. // distribution is subject to the Boost Software License, Version
  8. // 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. // This is a simplified/modified version of libs/thread/test/test_mutex.cpp
  11. // added to test boost::signals2::mutex.
  12. // For more information, see http://www.boost.org
  13. // note boost/test/minimal.hpp can cause windows.h to get included, which
  14. // can screw up our checks of _WIN32_WINNT if it is included
  15. // after boost/signals2/mutex.hpp. Frank Hess 2009-03-07.
  16. #include <boost/test/minimal.hpp>
  17. #include <boost/bind.hpp>
  18. #include <boost/signals2/dummy_mutex.hpp>
  19. #include <boost/signals2/mutex.hpp>
  20. #include <boost/thread/locks.hpp>
  21. #include <boost/thread/mutex.hpp>
  22. #include <boost/thread/thread.hpp>
  23. #include <boost/thread/thread_time.hpp>
  24. #include <boost/thread/condition.hpp>
  25. class execution_monitor
  26. {
  27. public:
  28. execution_monitor(int secs)
  29. : done(false), m_secs(secs) { }
  30. void start()
  31. {
  32. boost::mutex::scoped_lock lock(mutex);
  33. done = false;
  34. }
  35. void finish()
  36. {
  37. boost::mutex::scoped_lock lock(mutex);
  38. done = true;
  39. cond.notify_one();
  40. }
  41. bool wait()
  42. {
  43. boost::posix_time::time_duration timeout = boost::posix_time::seconds(m_secs);
  44. boost::mutex::scoped_lock lock(mutex);
  45. while (!done) {
  46. if (!cond.timed_wait(lock, timeout))
  47. break;
  48. }
  49. return done;
  50. }
  51. private:
  52. boost::mutex mutex;
  53. boost::condition cond;
  54. bool done;
  55. int m_secs;
  56. };
  57. template <typename F>
  58. class indirect_adapter
  59. {
  60. public:
  61. indirect_adapter(F func, execution_monitor& monitor)
  62. : m_func(func), m_monitor(monitor) { }
  63. void operator()() const
  64. {
  65. try
  66. {
  67. boost::thread thrd(m_func);
  68. thrd.join();
  69. }
  70. catch (...)
  71. {
  72. m_monitor.finish();
  73. throw;
  74. }
  75. m_monitor.finish();
  76. }
  77. private:
  78. F m_func;
  79. execution_monitor& m_monitor;
  80. void operator=(indirect_adapter&);
  81. };
  82. template <typename F>
  83. void timed_test(F func, int secs)
  84. {
  85. execution_monitor monitor(secs);
  86. indirect_adapter<F> ifunc(func, monitor);
  87. monitor.start();
  88. boost::thread thrd(ifunc);
  89. BOOST_REQUIRE(monitor.wait()); // Timed test didn't complete in time, possible deadlock
  90. }
  91. template <typename M>
  92. struct test_lock
  93. {
  94. typedef M mutex_type;
  95. typedef typename boost::unique_lock<M> lock_type;
  96. void operator()()
  97. {
  98. mutex_type mutex;
  99. boost::condition condition;
  100. // Test the lock's constructors.
  101. {
  102. lock_type lock(mutex, boost::defer_lock);
  103. BOOST_CHECK(!lock);
  104. }
  105. lock_type lock(mutex);
  106. BOOST_CHECK(lock ? true : false);
  107. // Construct a fast time out.
  108. boost::posix_time::time_duration timeout = boost::posix_time::milliseconds(100);
  109. // Test the lock and the mutex with condition variables.
  110. // No one is going to notify this condition variable. We expect to
  111. // time out.
  112. BOOST_CHECK(!condition.timed_wait(lock, timeout));
  113. BOOST_CHECK(lock ? true : false);
  114. // Test the lock and unlock methods.
  115. lock.unlock();
  116. BOOST_CHECK(!lock);
  117. lock.lock();
  118. BOOST_CHECK(lock ? true : false);
  119. }
  120. };
  121. template <typename M>
  122. struct test_trylock
  123. {
  124. typedef M mutex_type;
  125. typedef typename boost::unique_lock<M> lock_type;
  126. void operator()()
  127. {
  128. mutex_type mutex;
  129. boost::condition condition;
  130. // Test the lock's constructors.
  131. {
  132. lock_type lock(mutex, boost::try_to_lock);
  133. BOOST_CHECK(lock ? true : false);
  134. }
  135. {
  136. lock_type lock(mutex, boost::defer_lock);
  137. BOOST_CHECK(!lock);
  138. }
  139. lock_type lock(mutex, boost::try_to_lock);
  140. BOOST_CHECK(lock ? true : false);
  141. // Construct a fast time out.
  142. boost::posix_time::time_duration timeout = boost::posix_time::milliseconds(100);
  143. // Test the lock and the mutex with condition variables.
  144. // No one is going to notify this condition variable. We expect to
  145. // time out.
  146. BOOST_CHECK(!condition.timed_wait(lock, timeout));
  147. BOOST_CHECK(lock ? true : false);
  148. // Test the lock, unlock and trylock methods.
  149. lock.unlock();
  150. BOOST_CHECK(!lock);
  151. lock.lock();
  152. BOOST_CHECK(lock ? true : false);
  153. lock.unlock();
  154. BOOST_CHECK(!lock);
  155. BOOST_CHECK(lock.try_lock());
  156. BOOST_CHECK(lock ? true : false);
  157. }
  158. };
  159. template<typename Mutex>
  160. struct test_lock_exclusion
  161. {
  162. typedef boost::unique_lock<Mutex> Lock;
  163. Mutex m;
  164. boost::mutex done_mutex;
  165. bool done;
  166. bool locked;
  167. boost::condition_variable done_cond;
  168. test_lock_exclusion():
  169. done(false),locked(false)
  170. {}
  171. void locking_thread()
  172. {
  173. Lock lock(m);
  174. boost::lock_guard<boost::mutex> lk(done_mutex);
  175. locked=lock.owns_lock();
  176. done=true;
  177. done_cond.notify_one();
  178. }
  179. bool is_done() const
  180. {
  181. return done;
  182. }
  183. typedef test_lock_exclusion<Mutex> this_type;
  184. void do_test(void (this_type::*test_func)())
  185. {
  186. Lock lock(m);
  187. {
  188. boost::lock_guard<boost::mutex> lk(done_mutex);
  189. locked=false;
  190. }
  191. done=false;
  192. boost::thread t(test_func,this);
  193. try
  194. {
  195. {
  196. boost::mutex::scoped_lock lk(done_mutex);
  197. BOOST_CHECK(!done_cond.timed_wait(lk, boost::posix_time::seconds(1),
  198. boost::bind(&this_type::is_done,this)));
  199. }
  200. lock.unlock();
  201. {
  202. boost::mutex::scoped_lock lk(done_mutex);
  203. BOOST_CHECK(done_cond.timed_wait(lk, boost::posix_time::seconds(1),
  204. boost::bind(&this_type::is_done,this)));
  205. }
  206. t.join();
  207. BOOST_CHECK(locked);
  208. }
  209. catch(...)
  210. {
  211. lock.unlock();
  212. t.join();
  213. throw;
  214. }
  215. }
  216. void operator()()
  217. {
  218. do_test(&this_type::locking_thread);
  219. }
  220. };
  221. void do_test_mutex()
  222. {
  223. test_lock<boost::signals2::mutex>()();
  224. // try_lock not supported on old versions of windows
  225. #if !defined(BOOST_HAS_WINTHREADS) || (defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400))
  226. test_trylock<boost::signals2::mutex>()();
  227. #endif
  228. test_lock_exclusion<boost::signals2::mutex>()();
  229. }
  230. void test_mutex()
  231. {
  232. timed_test(&do_test_mutex, 3);
  233. }
  234. void do_test_dummy_mutex()
  235. {
  236. test_lock<boost::signals2::dummy_mutex>()();
  237. test_trylock<boost::signals2::dummy_mutex>()();
  238. }
  239. void test_dummy_mutex()
  240. {
  241. timed_test(&do_test_dummy_mutex, 2);
  242. }
  243. int test_main(int, char*[])
  244. {
  245. test_mutex();
  246. test_dummy_mutex();
  247. return 0;
  248. }