grammar_mt_tests.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. /*=============================================================================
  2. Copyright (c) 2003 Martin Wille
  3. http://spirit.sourceforge.net/
  4. Use, modification and distribution is subject to the Boost Software
  5. License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  6. http://www.boost.org/LICENSE_1_0.txt)
  7. =============================================================================*/
  8. #include <iostream>
  9. #include <boost/config.hpp>
  10. #include <boost/detail/lightweight_test.hpp>
  11. #if defined(DONT_HAVE_BOOST) || !defined(BOOST_HAS_THREADS) || defined(BOOST_DISABLE_THREADS)
  12. // we end here if we can't do multithreading
  13. static void skipped()
  14. {
  15. std::cout << "skipped\n";
  16. }
  17. int
  18. main()
  19. {
  20. skipped();
  21. return 0;
  22. }
  23. #else
  24. // the real MT stuff
  25. #undef BOOST_SPIRIT_THREADSAFE
  26. #define BOOST_SPIRIT_THREADSAFE
  27. #include <boost/thread/thread.hpp>
  28. #include <boost/spirit/include/classic_grammar.hpp>
  29. #include <boost/spirit/include/classic_rule.hpp>
  30. #include <boost/spirit/include/classic_epsilon.hpp>
  31. #include <boost/thread/xtime.hpp>
  32. #include <boost/thread/mutex.hpp>
  33. #include <boost/thread/lock_types.hpp>
  34. #include <boost/ref.hpp>
  35. static boost::mutex simple_mutex;
  36. static int simple_definition_count = 0;
  37. struct simple : public BOOST_SPIRIT_CLASSIC_NS::grammar<simple>
  38. {
  39. template <typename ScannerT>
  40. struct definition
  41. {
  42. definition(simple const& /*self*/)
  43. {
  44. top = BOOST_SPIRIT_CLASSIC_NS::epsilon_p;
  45. boost::unique_lock<boost::mutex> lock(simple_mutex);
  46. simple_definition_count++;
  47. }
  48. BOOST_SPIRIT_CLASSIC_NS::rule<ScannerT> top;
  49. BOOST_SPIRIT_CLASSIC_NS::rule<ScannerT> const &start() const { return top; }
  50. };
  51. };
  52. struct count_guard
  53. {
  54. count_guard(int &c) : counter(c) {}
  55. ~count_guard() { counter = 0; }
  56. private:
  57. int &counter;
  58. };
  59. static void
  60. milli_sleep(unsigned long milliseconds)
  61. {
  62. static long const nanoseconds_per_second = 1000L*1000L*1000L;
  63. boost::xtime xt;
  64. boost::xtime_get(&xt, boost::TIME_UTC_);
  65. xt.nsec+=1000*1000*milliseconds;
  66. while (xt.nsec > nanoseconds_per_second)
  67. {
  68. xt.nsec -= nanoseconds_per_second;
  69. xt.sec++;
  70. }
  71. boost::thread::sleep(xt);
  72. }
  73. static void
  74. nap()
  75. {
  76. // this function is called by various threads to ensure
  77. // that thread lifetime actually overlap
  78. milli_sleep(300);
  79. }
  80. template <typename GrammarT>
  81. static void
  82. make_definition(GrammarT &g)
  83. {
  84. char const *text="blah";
  85. BOOST_SPIRIT_CLASSIC_NS::scanner<> s(text, text+4);
  86. g.parse(s);
  87. }
  88. template <typename GrammarT>
  89. static void
  90. make_definition3(GrammarT &g)
  91. {
  92. char const *text="blah";
  93. BOOST_SPIRIT_CLASSIC_NS::scanner<> s(text, text+4);
  94. g.parse(s);
  95. nap();
  96. g.parse(s);
  97. g.parse(s);
  98. }
  99. ////////////////////////////////////////////////////////////////////////////////
  100. #define exactly_one_instance_created simple_definition_count == 1
  101. #define exactly_two_instances_created simple_definition_count == 2
  102. #define exactly_four_instances_created simple_definition_count == 4
  103. #define exactly_eight_instances_created simple_definition_count == 8
  104. ////////////////////////////////////////////////////////////////////////////////
  105. static void
  106. multiple_attempts_to_instantiate_a_definition_from_a_single_thread()
  107. {
  108. // checks wether exactly one definition per grammar
  109. // object is created
  110. count_guard guard(simple_definition_count);
  111. simple simple1_p;
  112. simple simple2_p;
  113. make_definition(simple1_p);
  114. make_definition(simple1_p);
  115. make_definition(simple1_p);
  116. BOOST_TEST(exactly_one_instance_created);
  117. make_definition(simple2_p);
  118. make_definition(simple2_p);
  119. make_definition(simple2_p);
  120. BOOST_TEST(exactly_two_instances_created);
  121. }
  122. ////////////////////////////////////////////////////////////////////////////////
  123. struct single_grammar_object_task
  124. {
  125. void operator()() const
  126. {
  127. make_definition3(simple1_p);
  128. };
  129. simple simple1_p;
  130. };
  131. ////////////////////////////////////////////////////////////////////////////////
  132. template <typename T>
  133. class callable_reference_wrapper
  134. : public boost::reference_wrapper<T>
  135. {
  136. public:
  137. explicit callable_reference_wrapper(T& t)
  138. : boost::reference_wrapper<T>(t)
  139. {}
  140. inline void operator()() { this->get().operator()(); }
  141. };
  142. template <typename T>
  143. callable_reference_wrapper<T>
  144. callable_ref(T &t)
  145. {
  146. return callable_reference_wrapper<T>(t);
  147. }
  148. ////////////////////////////////////////////////////////////////////////////////
  149. static void
  150. single_local_grammar_object_multiple_threads()
  151. {
  152. // check wether independent definition objects are
  153. // created
  154. count_guard guard(simple_definition_count);
  155. single_grammar_object_task task1, task2, task3, task4;
  156. boost::thread t1(callable_ref(task1));
  157. boost::thread t2(callable_ref(task2));
  158. boost::thread t3(callable_ref(task3));
  159. boost::thread t4(callable_ref(task4));
  160. t1.join();
  161. t2.join();
  162. t3.join();
  163. t4.join();
  164. BOOST_TEST(exactly_four_instances_created);
  165. }
  166. ////////////////////////////////////////////////////////////////////////////////
  167. struct two_grammar_objects_task
  168. {
  169. void operator()() const
  170. {
  171. make_definition3(simple1_p);
  172. make_definition3(simple2_p);
  173. };
  174. simple simple1_p;
  175. simple simple2_p;
  176. };
  177. static void
  178. multiple_local_grammar_objects_multiple_threads()
  179. {
  180. // check wether exactly one definition per thread
  181. // and per grammar object is created
  182. count_guard guard(simple_definition_count);
  183. two_grammar_objects_task task1, task2, task3, task4;
  184. boost::thread t1(callable_ref(task1));
  185. boost::thread t2(callable_ref(task2));
  186. boost::thread t3(callable_ref(task3));
  187. boost::thread t4(callable_ref(task4));
  188. t1.join();
  189. t2.join();
  190. t3.join();
  191. t4.join();
  192. BOOST_TEST(exactly_eight_instances_created);
  193. }
  194. ////////////////////////////////////////////////////////////////////////////////
  195. static simple global_simple1_p;
  196. struct single_global_grammar_object_task
  197. {
  198. void operator()() const
  199. {
  200. make_definition3(global_simple1_p);
  201. };
  202. };
  203. static void
  204. single_global_grammar_object_multiple_threads()
  205. {
  206. // check wether exactly one definition per thread is
  207. // created
  208. count_guard guard(simple_definition_count);
  209. single_global_grammar_object_task task1, task2, task3, task4;
  210. boost::thread t1(callable_ref(task1));
  211. boost::thread t2(callable_ref(task2));
  212. boost::thread t3(callable_ref(task3));
  213. boost::thread t4(callable_ref(task4));
  214. t1.join();
  215. t2.join();
  216. t3.join();
  217. t4.join();
  218. BOOST_TEST(exactly_four_instances_created);
  219. }
  220. ////////////////////////////////////////////////////////////////////////////////
  221. static simple global_simple2_p;
  222. static simple global_simple3_p;
  223. struct multiple_global_grammar_objects_task
  224. {
  225. void operator()() const
  226. {
  227. make_definition3(global_simple2_p);
  228. make_definition3(global_simple3_p);
  229. };
  230. };
  231. static void
  232. multiple_global_grammar_objects_multiple_threads()
  233. {
  234. // check wether exactly one definition per thread
  235. // and per grammar object is created
  236. count_guard guard(simple_definition_count);
  237. multiple_global_grammar_objects_task task1, task2, task3, task4;
  238. boost::thread t1(callable_ref(task1));
  239. boost::thread t2(callable_ref(task2));
  240. boost::thread t3(callable_ref(task3));
  241. boost::thread t4(callable_ref(task4));
  242. t1.join();
  243. t2.join();
  244. t3.join();
  245. t4.join();
  246. BOOST_TEST(exactly_eight_instances_created);
  247. }
  248. ////////////////////////////////////////////////////////////////////////////////
  249. int
  250. main()
  251. {
  252. multiple_attempts_to_instantiate_a_definition_from_a_single_thread();
  253. single_local_grammar_object_multiple_threads();
  254. multiple_local_grammar_objects_multiple_threads();
  255. single_global_grammar_object_multiple_threads();
  256. multiple_global_grammar_objects_multiple_threads();
  257. return boost::report_errors();
  258. }
  259. ////////////////////////////////////////////////////////////////////////////////
  260. static BOOST_SPIRIT_CLASSIC_NS::parse_info<char const *> pi;
  261. ////////////////////////////////////////////////
  262. // These macros are used with BOOST_TEST
  263. #endif // MT mode