condition_test_template.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. // Copyright (C) 2001-2003
  2. // William E. Kempf
  3. //
  4. // Permission to use, copy, modify, distribute and sell this software
  5. // and its documentation for any purpose is hereby granted without fee,
  6. // provided that the above copyright notice appear in all copies and
  7. // that both that copyright notice and this permission notice appear
  8. // in supporting documentation. William E. Kempf makes no representations
  9. // about the suitability of this software for any purpose.
  10. // It is provided "as is" without express or implied warranty.
  11. //////////////////////////////////////////////////////////////////////////////
  12. //
  13. // (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
  14. // Software License, Version 1.0. (See accompanying file
  15. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  16. //
  17. // See http://www.boost.org/libs/interprocess for documentation.
  18. //
  19. //////////////////////////////////////////////////////////////////////////////
  20. #ifndef BOOST_INTERPROCESS_CONDITION_TEST_TEMPLATE_HPP
  21. #define BOOST_INTERPROCESS_CONDITION_TEST_TEMPLATE_HPP
  22. #include <boost/interprocess/detail/config_begin.hpp>
  23. #include <boost/interprocess/detail/workaround.hpp>
  24. #include <boost/interprocess/detail/os_thread_functions.hpp>
  25. #include "boost_interprocess_check.hpp"
  26. #include <boost/interprocess/sync/scoped_lock.hpp>
  27. #include <boost/date_time/posix_time/posix_time_types.hpp>
  28. #include <iostream>
  29. namespace boost{
  30. namespace interprocess{
  31. namespace test {
  32. boost::posix_time::ptime ptime_delay(int secs)
  33. {
  34. return microsec_clock::universal_time() +
  35. boost::posix_time::time_duration(0, 0, secs);
  36. }
  37. template <typename F, typename T>
  38. class binder
  39. {
  40. public:
  41. binder(const F& f, const T& p)
  42. : func(f), param(p) { }
  43. void operator()() const { func(param); }
  44. private:
  45. F func;
  46. T param;
  47. };
  48. template <typename F, typename T>
  49. binder<F, T> bind_function(F func, T param)
  50. {
  51. return binder<F, T>(func, param);
  52. }
  53. template <class Condition, class Mutex>
  54. struct condition_test_data
  55. {
  56. condition_test_data() : notified(0), awoken(0) { }
  57. ~condition_test_data()
  58. {}
  59. Mutex mutex;
  60. Condition condition;
  61. int notified;
  62. int awoken;
  63. };
  64. template <class Condition, class Mutex>
  65. void condition_test_thread(condition_test_data<Condition, Mutex>* data)
  66. {
  67. boost::interprocess::scoped_lock<Mutex>
  68. lock(data->mutex);
  69. BOOST_INTERPROCESS_CHECK(lock ? true : false);
  70. while (!(data->notified > 0))
  71. data->condition.wait(lock);
  72. BOOST_INTERPROCESS_CHECK(lock ? true : false);
  73. data->awoken++;
  74. }
  75. struct cond_predicate
  76. {
  77. cond_predicate(int& var, int val) : _var(var), _val(val) { }
  78. bool operator()() { return _var == _val; }
  79. int& _var;
  80. int _val;
  81. };
  82. template <class Condition, class Mutex>
  83. void condition_test_waits(condition_test_data<Condition, Mutex>* data)
  84. {
  85. boost::interprocess::scoped_lock<Mutex>
  86. lock(data->mutex);
  87. BOOST_INTERPROCESS_CHECK(lock ? true : false);
  88. // Test wait.
  89. while (data->notified != 1)
  90. data->condition.wait(lock);
  91. BOOST_INTERPROCESS_CHECK(lock ? true : false);
  92. BOOST_INTERPROCESS_CHECK(data->notified == 1);
  93. data->awoken++;
  94. data->condition.notify_one();
  95. // Test predicate wait.
  96. data->condition.wait(lock, cond_predicate(data->notified, 2));
  97. BOOST_INTERPROCESS_CHECK(lock ? true : false);
  98. BOOST_INTERPROCESS_CHECK(data->notified == 2);
  99. data->awoken++;
  100. data->condition.notify_one();
  101. // Test timed_wait.
  102. while (data->notified != 3)
  103. data->condition.timed_wait(lock, ptime_delay(5));
  104. BOOST_INTERPROCESS_CHECK(lock ? true : false);
  105. BOOST_INTERPROCESS_CHECK(data->notified == 3);
  106. data->awoken++;
  107. data->condition.notify_one();
  108. // Test predicate timed_wait.
  109. cond_predicate pred(data->notified, 4);
  110. bool ret = data->condition.timed_wait(lock, ptime_delay(5), pred);
  111. BOOST_INTERPROCESS_CHECK(ret);(void)ret;
  112. BOOST_INTERPROCESS_CHECK(lock ? true : false);
  113. BOOST_INTERPROCESS_CHECK(pred());
  114. BOOST_INTERPROCESS_CHECK(data->notified == 4);
  115. data->awoken++;
  116. data->condition.notify_one();
  117. }
  118. template <class Condition, class Mutex>
  119. void do_test_condition_notify_one()
  120. {
  121. condition_test_data<Condition, Mutex> data;
  122. boost::interprocess::ipcdetail::OS_thread_t thread;
  123. boost::interprocess::ipcdetail::thread_launch(thread, bind_function(&condition_test_thread<Condition, Mutex>, &data));
  124. //Make sure thread is blocked
  125. boost::interprocess::ipcdetail::thread_sleep(1000);
  126. {
  127. boost::interprocess::scoped_lock<Mutex>
  128. lock(data.mutex);
  129. BOOST_INTERPROCESS_CHECK(lock ? true : false);
  130. data.notified++;
  131. data.condition.notify_one();
  132. }
  133. boost::interprocess::ipcdetail::thread_join(thread);
  134. BOOST_INTERPROCESS_CHECK(data.awoken == 1);
  135. }
  136. template <class Condition, class Mutex>
  137. void do_test_condition_notify_all()
  138. {
  139. const int NUMTHREADS = 3;
  140. boost::interprocess::ipcdetail::OS_thread_t thgroup[NUMTHREADS];
  141. condition_test_data<Condition, Mutex> data;
  142. for(int i = 0; i< NUMTHREADS; ++i){
  143. boost::interprocess::ipcdetail::thread_launch(thgroup[i], bind_function(&condition_test_thread<Condition, Mutex>, &data));
  144. }
  145. //Make sure all threads are blocked
  146. boost::interprocess::ipcdetail::thread_sleep(1000);
  147. {
  148. boost::interprocess::scoped_lock<Mutex>
  149. lock(data.mutex);
  150. BOOST_INTERPROCESS_CHECK(lock ? true : false);
  151. data.notified++;
  152. }
  153. data.condition.notify_all();
  154. for(int i = 0; i< NUMTHREADS; ++i){
  155. boost::interprocess::ipcdetail::thread_join(thgroup[i]);
  156. }
  157. BOOST_INTERPROCESS_CHECK(data.awoken == NUMTHREADS);
  158. }
  159. template <class Condition, class Mutex>
  160. void do_test_condition_waits()
  161. {
  162. condition_test_data<Condition, Mutex> data;
  163. boost::interprocess::ipcdetail::OS_thread_t thread;
  164. boost::interprocess::ipcdetail::thread_launch(thread, bind_function(&condition_test_waits<Condition, Mutex>, &data));
  165. {
  166. boost::interprocess::scoped_lock<Mutex>
  167. lock(data.mutex);
  168. BOOST_INTERPROCESS_CHECK(lock ? true : false);
  169. boost::interprocess::ipcdetail::thread_sleep(1000);
  170. data.notified++;
  171. data.condition.notify_one();
  172. while (data.awoken != 1)
  173. data.condition.wait(lock);
  174. BOOST_INTERPROCESS_CHECK(lock ? true : false);
  175. BOOST_INTERPROCESS_CHECK(data.awoken == 1);
  176. boost::interprocess::ipcdetail::thread_sleep(1000);
  177. data.notified++;
  178. data.condition.notify_one();
  179. while (data.awoken != 2)
  180. data.condition.wait(lock);
  181. BOOST_INTERPROCESS_CHECK(lock ? true : false);
  182. BOOST_INTERPROCESS_CHECK(data.awoken == 2);
  183. boost::interprocess::ipcdetail::thread_sleep(1000);
  184. data.notified++;
  185. data.condition.notify_one();
  186. while (data.awoken != 3)
  187. data.condition.wait(lock);
  188. BOOST_INTERPROCESS_CHECK(lock ? true : false);
  189. BOOST_INTERPROCESS_CHECK(data.awoken == 3);
  190. boost::interprocess::ipcdetail::thread_sleep(1000);
  191. data.notified++;
  192. data.condition.notify_one();
  193. while (data.awoken != 4)
  194. data.condition.wait(lock);
  195. BOOST_INTERPROCESS_CHECK(lock ? true : false);
  196. BOOST_INTERPROCESS_CHECK(data.awoken == 4);
  197. }
  198. boost::interprocess::ipcdetail::thread_join(thread);
  199. BOOST_INTERPROCESS_CHECK(data.awoken == 4);
  200. }
  201. /*
  202. //Message queue simulation test
  203. template <class Condition>
  204. inline Condition &cond_empty()
  205. {
  206. static Condition cond_empty;
  207. return cond_empty;
  208. }
  209. template <class Condition>
  210. inline Condition &cond_full()
  211. {
  212. static Condition cond_full;
  213. return cond_full;
  214. }
  215. template <class Mutex>
  216. inline Mutex &mutex()
  217. {
  218. static Mutex mut;
  219. return mut;
  220. }
  221. */
  222. static volatile int count = 0;
  223. static volatile int waiting_readers = 0;
  224. static volatile int waiting_writer = 0;
  225. const int queue_size = 3;
  226. const int thread_factor = 10;
  227. const int NumThreads = thread_factor*queue_size;
  228. //Function that removes items from queue
  229. template <class Condition, class Mutex>
  230. struct condition_func
  231. {
  232. condition_func(Condition &cond_full, Condition &cond_empty, Mutex &mutex)
  233. : cond_full_(cond_full), cond_empty_(cond_empty), mutex_(mutex)
  234. {}
  235. void operator()()
  236. {
  237. boost::interprocess::scoped_lock<Mutex>lock(mutex_);
  238. while(count == 0){
  239. ++waiting_readers;
  240. cond_empty_.wait(lock);
  241. --waiting_readers;
  242. }
  243. --count;
  244. if(waiting_writer)
  245. cond_full_.notify_one();
  246. }
  247. Condition &cond_full_;
  248. Condition &cond_empty_;
  249. Mutex &mutex_;
  250. };
  251. //Queue functions
  252. template <class Condition, class Mutex>
  253. void do_test_condition_queue_notify_one(void)
  254. {
  255. //Force mutex and condition creation
  256. Condition cond_empty;
  257. Condition cond_full;
  258. Mutex mutex;
  259. //Create threads that will decrease count
  260. {
  261. //Initialize counters
  262. count = 0;
  263. waiting_readers = 0;
  264. waiting_writer = 0;
  265. boost::interprocess::ipcdetail::OS_thread_t thgroup[NumThreads];
  266. for(int i = 0; i< NumThreads; ++i){
  267. condition_func<Condition, Mutex> func(cond_full, cond_empty, mutex);
  268. boost::interprocess::ipcdetail::thread_launch(thgroup[i], func);
  269. }
  270. //Add 20 elements one by one in the queue simulation
  271. //The sender will block if it fills the queue
  272. for(int i = 0; i < NumThreads; ++i){
  273. boost::interprocess::scoped_lock<Mutex> lock(mutex);
  274. while(count == queue_size){
  275. ++waiting_writer;
  276. cond_full.wait(lock);
  277. --waiting_writer;
  278. }
  279. count++;
  280. if(waiting_readers)
  281. cond_empty.notify_one();
  282. }
  283. for(int i = 0; i< NumThreads; ++i){
  284. boost::interprocess::ipcdetail::thread_join(thgroup[i]);
  285. }
  286. BOOST_INTERPROCESS_CHECK(count == 0);
  287. BOOST_INTERPROCESS_CHECK(waiting_readers == 0);
  288. BOOST_INTERPROCESS_CHECK(waiting_writer == 0);
  289. }
  290. }
  291. //Queue functions
  292. template <class Condition, class Mutex>
  293. void do_test_condition_queue_notify_all(void)
  294. {
  295. //Force mutex and condition creation
  296. Condition cond_empty;
  297. Condition cond_full;
  298. Mutex mutex;
  299. //Create threads that will decrease count
  300. {
  301. //Initialize counters
  302. count = 0;
  303. waiting_readers = 0;
  304. waiting_writer = 0;
  305. boost::interprocess::ipcdetail::OS_thread_t thgroup[NumThreads];
  306. for(int i = 0; i< NumThreads; ++i){
  307. condition_func<Condition, Mutex> func(cond_full, cond_empty, mutex);
  308. boost::interprocess::ipcdetail::thread_launch(thgroup[i], func);
  309. }
  310. //Fill queue to the max size and notify all several times
  311. for(int i = 0; i < NumThreads; ++i){
  312. boost::interprocess::scoped_lock<Mutex>lock(mutex);
  313. while(count == queue_size){
  314. ++waiting_writer;
  315. cond_full.wait(lock);
  316. --waiting_writer;
  317. }
  318. count++;
  319. if(waiting_readers)
  320. cond_empty.notify_all();
  321. }
  322. for(int i = 0; i< NumThreads; ++i){
  323. boost::interprocess::ipcdetail::thread_join(thgroup[i]);
  324. }
  325. BOOST_INTERPROCESS_CHECK(count == 0);
  326. BOOST_INTERPROCESS_CHECK(waiting_readers == 0);
  327. BOOST_INTERPROCESS_CHECK(waiting_writer == 0);
  328. }
  329. }
  330. template <class Condition, class Mutex>
  331. bool do_test_condition()
  332. {
  333. std::cout << "do_test_condition_notify_one<" << typeid(Condition).name() << "," << typeid(Mutex).name() << '\n' << std::endl;
  334. do_test_condition_notify_one<Condition, Mutex>();
  335. std::cout << "do_test_condition_notify_all<" << typeid(Condition).name() << "," << typeid(Mutex).name() << '\n' << std::endl;
  336. do_test_condition_notify_all<Condition, Mutex>();
  337. std::cout << "do_test_condition_waits<" << typeid(Condition).name() << "," << typeid(Mutex).name() << '\n' << std::endl;
  338. do_test_condition_waits<Condition, Mutex>();
  339. std::cout << "do_test_condition_queue_notify_one<" << typeid(Condition).name() << "," << typeid(Mutex).name() << '\n' << std::endl;
  340. do_test_condition_queue_notify_one<Condition, Mutex>();
  341. std::cout << "do_test_condition_queue_notify_all<" << typeid(Condition).name() << "," << typeid(Mutex).name() << '\n' << std::endl;
  342. do_test_condition_queue_notify_all<Condition, Mutex>();
  343. return true;
  344. }
  345. } //namespace test
  346. } //namespace interprocess{
  347. } //namespace boost{
  348. #include <boost/interprocess/detail/config_end.hpp>
  349. #endif //#ifndef BOOST_INTERPROCESS_CONDITION_TEST_TEMPLATE_HPP