mutex_test_template.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost
  4. // Software License, Version 1.0. (See accompanying file
  5. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // See http://www.boost.org/libs/interprocess for documentation.
  8. //
  9. //////////////////////////////////////////////////////////////////////////////
  10. // Copyright (C) 2001-2003
  11. // William E. Kempf
  12. //
  13. // Permission to use, copy, modify, distribute and sell this software
  14. // and its documentation for any purpose is hereby granted without fee,
  15. // provided that the above copyright notice appear in all copies and
  16. // that both that copyright notice and this permission notice appear
  17. // in supporting documentation. William E. Kempf makes no representations
  18. // about the suitability of this software for any purpose.
  19. // It is provided "as is" without express or implied warranty.
  20. #ifndef BOOST_INTERPROCESS_TEST_MUTEX_TEST_TEMPLATE_HEADER
  21. #define BOOST_INTERPROCESS_TEST_MUTEX_TEST_TEMPLATE_HEADER
  22. #include <boost/interprocess/detail/config_begin.hpp>
  23. #include <boost/interprocess/exceptions.hpp>
  24. #include "boost_interprocess_check.hpp"
  25. #include "util.hpp"
  26. #include <boost/interprocess/detail/os_thread_functions.hpp>
  27. #include <boost/interprocess/sync/scoped_lock.hpp>
  28. #include <boost/date_time/posix_time/posix_time_types.hpp>
  29. #include <iostream>
  30. namespace boost { namespace interprocess { namespace test {
  31. template <typename M>
  32. struct test_lock
  33. {
  34. typedef M mutex_type;
  35. typedef boost::interprocess::scoped_lock<mutex_type> lock_type;
  36. void operator()()
  37. {
  38. mutex_type interprocess_mutex;
  39. // Test the lock's constructors.
  40. {
  41. lock_type lock(interprocess_mutex, boost::interprocess::defer_lock);
  42. BOOST_INTERPROCESS_CHECK(!lock);
  43. }
  44. lock_type lock(interprocess_mutex);
  45. BOOST_INTERPROCESS_CHECK(lock ? true : false);
  46. // Test the lock and unlock methods.
  47. lock.unlock();
  48. BOOST_INTERPROCESS_CHECK(!lock);
  49. lock.lock();
  50. BOOST_INTERPROCESS_CHECK(lock ? true : false);
  51. }
  52. };
  53. template <typename M>
  54. struct test_trylock
  55. {
  56. typedef M mutex_type;
  57. typedef boost::interprocess::scoped_lock<mutex_type> try_to_lock_type;
  58. void operator()()
  59. {
  60. mutex_type interprocess_mutex;
  61. // Test the lock's constructors.
  62. {
  63. try_to_lock_type lock(interprocess_mutex, boost::interprocess::try_to_lock);
  64. BOOST_INTERPROCESS_CHECK(lock ? true : false);
  65. }
  66. {
  67. try_to_lock_type lock(interprocess_mutex, boost::interprocess::defer_lock);
  68. BOOST_INTERPROCESS_CHECK(!lock);
  69. }
  70. try_to_lock_type lock(interprocess_mutex);
  71. BOOST_INTERPROCESS_CHECK(lock ? true : false);
  72. // Test the lock, unlock and trylock methods.
  73. lock.unlock();
  74. BOOST_INTERPROCESS_CHECK(!lock);
  75. lock.lock();
  76. BOOST_INTERPROCESS_CHECK(lock ? true : false);
  77. lock.unlock();
  78. BOOST_INTERPROCESS_CHECK(!lock);
  79. BOOST_INTERPROCESS_CHECK(lock.try_lock());
  80. BOOST_INTERPROCESS_CHECK(lock ? true : false);
  81. }
  82. };
  83. template <typename M>
  84. struct test_timedlock
  85. {
  86. typedef M mutex_type;
  87. typedef boost::interprocess::scoped_lock<mutex_type> timed_lock_type;
  88. void operator()()
  89. {
  90. mutex_type interprocess_mutex;
  91. // Test the lock's constructors.
  92. {
  93. // Construct and initialize an ptime for a fast time out.
  94. boost::posix_time::ptime pt = delay(1*BaseSeconds, 0);
  95. timed_lock_type lock(interprocess_mutex, pt);
  96. BOOST_INTERPROCESS_CHECK(lock ? true : false);
  97. }
  98. {
  99. timed_lock_type lock(interprocess_mutex, boost::interprocess::defer_lock);
  100. BOOST_INTERPROCESS_CHECK(!lock);
  101. }
  102. timed_lock_type lock(interprocess_mutex);
  103. BOOST_INTERPROCESS_CHECK(lock ? true : false);
  104. // Test the lock, unlock and timedlock methods.
  105. lock.unlock();
  106. BOOST_INTERPROCESS_CHECK(!lock);
  107. lock.lock();
  108. BOOST_INTERPROCESS_CHECK(lock ? true : false);
  109. lock.unlock();
  110. BOOST_INTERPROCESS_CHECK(!lock);
  111. boost::posix_time::ptime pt = delay(3*BaseSeconds, 0);
  112. BOOST_INTERPROCESS_CHECK(lock.timed_lock(pt));
  113. BOOST_INTERPROCESS_CHECK(lock ? true : false);
  114. }
  115. };
  116. template <typename M>
  117. struct test_recursive_lock
  118. {
  119. typedef M mutex_type;
  120. typedef boost::interprocess::scoped_lock<mutex_type> lock_type;
  121. void operator()()
  122. {
  123. mutex_type mx;
  124. {
  125. lock_type lock1(mx);
  126. lock_type lock2(mx);
  127. }
  128. {
  129. lock_type lock1(mx, defer_lock);
  130. lock_type lock2(mx, defer_lock);
  131. }
  132. {
  133. lock_type lock1(mx, try_to_lock);
  134. lock_type lock2(mx, try_to_lock);
  135. }
  136. {
  137. //This should always lock
  138. boost::posix_time::ptime pt = delay(2*BaseSeconds);
  139. lock_type lock1(mx, pt);
  140. lock_type lock2(mx, pt);
  141. }
  142. }
  143. };
  144. // plain_exclusive exercises the "infinite" lock for each
  145. // read_write_mutex type.
  146. template<typename M>
  147. void lock_and_sleep(void *arg, M &sm)
  148. {
  149. data<M> *pdata = static_cast<data<M>*>(arg);
  150. boost::interprocess::scoped_lock<M> l(sm);
  151. if(pdata->m_secs){
  152. boost::interprocess::ipcdetail::thread_sleep((1000*pdata->m_secs));
  153. }
  154. else{
  155. boost::interprocess::ipcdetail::thread_sleep((1000*2*BaseSeconds));
  156. }
  157. ++shared_val;
  158. pdata->m_value = shared_val;
  159. }
  160. template<typename M>
  161. void lock_and_catch_errors(void *arg, M &sm)
  162. {
  163. data<M> *pdata = static_cast<data<M>*>(arg);
  164. try
  165. {
  166. boost::interprocess::scoped_lock<M> l(sm);
  167. if(pdata->m_secs){
  168. boost::interprocess::ipcdetail::thread_sleep((1000*pdata->m_secs));
  169. }
  170. else{
  171. boost::interprocess::ipcdetail::thread_sleep((1000*2*BaseSeconds));
  172. }
  173. ++shared_val;
  174. pdata->m_value = shared_val;
  175. }
  176. catch(interprocess_exception const & e)
  177. {
  178. pdata->m_error = e.get_error_code();
  179. }
  180. }
  181. template<typename M>
  182. void try_lock_and_sleep(void *arg, M &sm)
  183. {
  184. data<M> *pdata = static_cast<data<M>*>(arg);
  185. boost::interprocess::scoped_lock<M> l(sm, boost::interprocess::defer_lock);
  186. if (l.try_lock()){
  187. boost::interprocess::ipcdetail::thread_sleep((1000*2*BaseSeconds));
  188. ++shared_val;
  189. pdata->m_value = shared_val;
  190. }
  191. }
  192. template<typename M>
  193. void timed_lock_and_sleep(void *arg, M &sm)
  194. {
  195. data<M> *pdata = static_cast<data<M>*>(arg);
  196. boost::posix_time::ptime pt(delay(pdata->m_secs));
  197. boost::interprocess::scoped_lock<M>
  198. l (sm, boost::interprocess::defer_lock);
  199. if (l.timed_lock(pt)){
  200. boost::interprocess::ipcdetail::thread_sleep((1000*2*BaseSeconds));
  201. ++shared_val;
  202. pdata->m_value = shared_val;
  203. }
  204. }
  205. template<typename M>
  206. void test_mutex_lock()
  207. {
  208. shared_val = 0;
  209. M mtx;
  210. data<M> d1(1);
  211. data<M> d2(2);
  212. // Locker one launches, holds the lock for 2*BaseSeconds seconds.
  213. boost::interprocess::ipcdetail::OS_thread_t tm1;
  214. boost::interprocess::ipcdetail::thread_launch(tm1, thread_adapter<M>(&lock_and_sleep, &d1, mtx));
  215. //Wait 1*BaseSeconds
  216. boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds));
  217. // Locker two launches, but it won't hold the lock for 2*BaseSeconds seconds.
  218. boost::interprocess::ipcdetail::OS_thread_t tm2;
  219. boost::interprocess::ipcdetail::thread_launch(tm2, thread_adapter<M>(&lock_and_sleep, &d2, mtx));
  220. //Wait completion
  221. boost::interprocess::ipcdetail::thread_join(tm1);
  222. boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds));
  223. boost::interprocess::ipcdetail::thread_join(tm2);
  224. BOOST_INTERPROCESS_CHECK(d1.m_value == 1);
  225. BOOST_INTERPROCESS_CHECK(d2.m_value == 2);
  226. }
  227. template<typename M>
  228. void test_mutex_lock_timeout()
  229. {
  230. shared_val = 0;
  231. M mtx;
  232. int wait_time_s = BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS / 1000;
  233. if (wait_time_s == 0 )
  234. wait_time_s = 1;
  235. data<M> d1(1, wait_time_s * 3);
  236. data<M> d2(2, wait_time_s * 2);
  237. // Locker one launches, and holds the lock for wait_time_s * 2 seconds.
  238. boost::interprocess::ipcdetail::OS_thread_t tm1;
  239. boost::interprocess::ipcdetail::thread_launch(tm1, thread_adapter<M>(&lock_and_sleep, &d1, mtx));
  240. //Wait 1*BaseSeconds
  241. boost::interprocess::ipcdetail::thread_sleep((1000*wait_time_s));
  242. // Locker two launches, and attempts to hold the lock for wait_time_s * 2 seconds.
  243. boost::interprocess::ipcdetail::OS_thread_t tm2;
  244. boost::interprocess::ipcdetail::thread_launch(tm2, thread_adapter<M>(&lock_and_catch_errors, &d2, mtx));
  245. //Wait completion
  246. boost::interprocess::ipcdetail::thread_join(tm1);
  247. boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds));
  248. boost::interprocess::ipcdetail::thread_join(tm2);
  249. BOOST_INTERPROCESS_CHECK(d1.m_value == 1);
  250. BOOST_INTERPROCESS_CHECK(d2.m_value == -1);
  251. BOOST_INTERPROCESS_CHECK(d1.m_error == no_error);
  252. BOOST_INTERPROCESS_CHECK(d2.m_error == boost::interprocess::timeout_when_locking_error);
  253. }
  254. template<typename M>
  255. void test_mutex_try_lock()
  256. {
  257. shared_val = 0;
  258. M mtx;
  259. data<M> d1(1);
  260. data<M> d2(2);
  261. // Locker one launches, holds the lock for 2*BaseSeconds seconds.
  262. boost::interprocess::ipcdetail::OS_thread_t tm1;
  263. boost::interprocess::ipcdetail::thread_launch(tm1, thread_adapter<M>(&try_lock_and_sleep, &d1, mtx));
  264. //Wait 1*BaseSeconds
  265. boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds));
  266. // Locker two launches, but it should fail acquiring the lock
  267. boost::interprocess::ipcdetail::OS_thread_t tm2;
  268. boost::interprocess::ipcdetail::thread_launch(tm2, thread_adapter<M>(&try_lock_and_sleep, &d2, mtx));
  269. //Wait completion
  270. boost::interprocess::ipcdetail::thread_join(tm1);
  271. boost::interprocess::ipcdetail::thread_join(tm2);
  272. //Only the first should succeed locking
  273. BOOST_INTERPROCESS_CHECK(d1.m_value == 1);
  274. BOOST_INTERPROCESS_CHECK(d2.m_value == -1);
  275. }
  276. template<typename M>
  277. void test_mutex_timed_lock()
  278. {
  279. shared_val = 0;
  280. M mtx, m2;
  281. data<M> d1(1, 2*BaseSeconds);
  282. data<M> d2(2, 2*BaseSeconds);
  283. // Locker one launches, holds the lock for 2*BaseSeconds seconds.
  284. boost::interprocess::ipcdetail::OS_thread_t tm1;
  285. boost::interprocess::ipcdetail::thread_launch(tm1, thread_adapter<M>(&timed_lock_and_sleep, &d1, mtx));
  286. //Wait 1*BaseSeconds
  287. boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds));
  288. // Locker two launches, holds the lock for 2*BaseSeconds seconds.
  289. boost::interprocess::ipcdetail::OS_thread_t tm2;
  290. boost::interprocess::ipcdetail::thread_launch(tm2, thread_adapter<M>(&timed_lock_and_sleep, &d2, mtx));
  291. //Wait completion
  292. boost::interprocess::ipcdetail::thread_join(tm1);
  293. boost::interprocess::ipcdetail::thread_join(tm2);
  294. //Both should succeed locking
  295. BOOST_INTERPROCESS_CHECK(d1.m_value == 1);
  296. BOOST_INTERPROCESS_CHECK(d2.m_value == 2);
  297. }
  298. template <typename M>
  299. inline void test_all_lock()
  300. {
  301. //Now generic interprocess_mutex tests
  302. std::cout << "test_lock<" << typeid(M).name() << ">" << std::endl;
  303. test_lock<M>()();
  304. std::cout << "test_trylock<" << typeid(M).name() << ">" << std::endl;
  305. test_trylock<M>()();
  306. std::cout << "test_timedlock<" << typeid(M).name() << ">" << std::endl;
  307. test_timedlock<M>()();
  308. }
  309. template <typename M>
  310. inline void test_all_recursive_lock()
  311. {
  312. //Now generic interprocess_mutex tests
  313. std::cout << "test_recursive_lock<" << typeid(M).name() << ">" << std::endl;
  314. test_recursive_lock<M>()();
  315. }
  316. template<typename M>
  317. void test_all_mutex()
  318. {
  319. std::cout << "test_mutex_lock<" << typeid(M).name() << ">" << std::endl;
  320. test_mutex_lock<M>();
  321. std::cout << "test_mutex_try_lock<" << typeid(M).name() << ">" << std::endl;
  322. test_mutex_try_lock<M>();
  323. std::cout << "test_mutex_timed_lock<" << typeid(M).name() << ">" << std::endl;
  324. test_mutex_timed_lock<M>();
  325. }
  326. }}} //namespace boost { namespace interprocess { namespace test {
  327. #include <boost/interprocess/detail/config_end.hpp>
  328. #endif //BOOST_INTERPROCESS_TEST_MUTEX_TEST_TEMPLATE_HEADER