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