]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | #ifndef BOOST_THREAD_EXPERIMENTAL_PARALLEL_V2_TASK_REGION_HPP |
2 | #define BOOST_THREAD_EXPERIMENTAL_PARALLEL_V2_TASK_REGION_HPP | |
3 | ||
4 | ////////////////////////////////////////////////////////////////////////////// | |
5 | // | |
6 | // (C) Copyright Vicente J. Botet Escriba 2014-2015. Distributed under the Boost | |
7 | // Software License, Version 1.0. (See accompanying file | |
8 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
9 | // | |
10 | // See http://www.boost.org/libs/thread for documentation. | |
11 | // | |
12 | ////////////////////////////////////////////////////////////////////////////// | |
13 | #include <boost/thread/detail/config.hpp> | |
14 | ||
15 | #include <boost/thread/future.hpp> | |
16 | #if defined BOOST_THREAD_PROVIDES_EXECUTORS | |
17 | #include <boost/thread/executors/basic_thread_pool.hpp> | |
18 | #endif | |
19 | #include <boost/thread/experimental/exception_list.hpp> | |
20 | #include <boost/thread/experimental/parallel/v2/inline_namespace.hpp> | |
21 | #include <boost/thread/detail/move.hpp> | |
22 | ||
23 | #include <boost/config/abi_prefix.hpp> | |
24 | ||
25 | #define BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED | |
26 | ||
27 | namespace boost | |
28 | { | |
29 | namespace experimental | |
30 | { | |
31 | namespace parallel | |
32 | { | |
33 | BOOST_THREAD_INLINE_NAMESPACE(v2) | |
34 | { | |
35 | class BOOST_SYMBOL_VISIBLE task_canceled_exception: public std::exception | |
36 | { | |
37 | public: | |
38 | //task_canceled_exception() BOOST_NOEXCEPT {} | |
39 | //task_canceled_exception(const task_canceled_exception&) BOOST_NOEXCEPT {} | |
40 | //task_canceled_exception& operator=(const task_canceled_exception&) BOOST_NOEXCEPT {} | |
41 | virtual const char* what() const BOOST_NOEXCEPT_OR_NOTHROW | |
42 | { return "task_canceled_exception";} | |
43 | }; | |
44 | ||
45 | template <class Executor> | |
46 | class task_region_handle_gen; | |
47 | ||
48 | namespace detail | |
49 | { | |
50 | void handle_task_region_exceptions(exception_list& errors) | |
51 | { | |
52 | try { | |
53 | throw; | |
54 | } | |
55 | #if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED | |
56 | catch (task_canceled_exception&) | |
57 | { | |
58 | } | |
59 | #endif | |
60 | catch (exception_list const& el) | |
61 | { | |
62 | for (exception_list::const_iterator it = el.begin(); it != el.end(); ++it) | |
63 | { | |
64 | boost::exception_ptr const& e = *it; | |
65 | try { | |
66 | rethrow_exception(e); | |
67 | } | |
68 | catch (...) | |
69 | { | |
70 | handle_task_region_exceptions(errors); | |
71 | } | |
72 | } | |
73 | } | |
74 | catch (...) | |
75 | { | |
76 | errors.add(boost::current_exception()); | |
77 | } | |
78 | } | |
79 | ||
80 | #if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED | |
81 | template <class TRH, class F> | |
82 | struct wrapped | |
83 | { | |
84 | TRH& tr; | |
85 | F f; | |
86 | wrapped(TRH& tr, BOOST_THREAD_RV_REF(F) f) : tr(tr), f(move(f)) | |
87 | {} | |
88 | void operator()() | |
89 | { | |
90 | try | |
91 | { | |
92 | f(); | |
93 | } | |
94 | catch (...) | |
95 | { | |
96 | lock_guard<mutex> lk(tr.mtx); | |
97 | tr.canceled = true; | |
98 | throw; | |
99 | } | |
100 | } | |
101 | }; | |
102 | #endif | |
103 | } | |
104 | ||
105 | template <class Executor> | |
106 | class task_region_handle_gen | |
107 | { | |
108 | private: | |
109 | // Private members and friends | |
110 | #if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED | |
111 | template <class TRH, class F> | |
112 | friend struct detail::wrapped; | |
113 | #endif | |
114 | template <typename F> | |
115 | friend void task_region(BOOST_THREAD_FWD_REF(F) f); | |
116 | template<typename F> | |
117 | friend void task_region_final(BOOST_THREAD_FWD_REF(F) f); | |
118 | template <class Ex, typename F> | |
119 | friend void task_region(Ex&, BOOST_THREAD_FWD_REF(F) f); | |
120 | template<class Ex, typename F> | |
121 | friend void task_region_final(Ex&, BOOST_THREAD_FWD_REF(F) f); | |
122 | ||
123 | void wait_all() | |
124 | { | |
125 | wait_for_all(group.begin(), group.end()); | |
126 | ||
127 | for (group_type::iterator it = group.begin(); it != group.end(); ++it) | |
128 | { | |
129 | future<void>& f = *it; | |
130 | if (f.has_exception()) | |
131 | { | |
132 | try | |
133 | { | |
134 | boost::rethrow_exception(f.get_exception_ptr()); | |
135 | } | |
136 | catch (...) | |
137 | { | |
138 | detail::handle_task_region_exceptions(exs); | |
139 | } | |
140 | } | |
141 | } | |
142 | if (exs.size() != 0) | |
143 | { | |
144 | boost::throw_exception(exs); | |
145 | } | |
146 | } | |
147 | protected: | |
148 | #if ! defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED && ! defined BOOST_THREAD_PROVIDES_EXECUTORS | |
149 | task_region_handle_gen() | |
150 | {} | |
151 | #endif | |
152 | ||
153 | #if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED && defined BOOST_THREAD_PROVIDES_EXECUTORS | |
154 | task_region_handle_gen() | |
155 | : canceled(false) | |
156 | , ex(0) | |
157 | {} | |
158 | task_region_handle_gen(Executor& ex) | |
159 | : canceled(false) | |
160 | , ex(&ex) | |
161 | {} | |
162 | ||
163 | #endif | |
164 | ||
165 | #if ! defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED && defined BOOST_THREAD_PROVIDES_EXECUTORS | |
166 | task_region_handle_gen() | |
167 | : ex(0) | |
168 | {} | |
169 | task_region_handle_gen(Executor& ex) | |
170 | : ex(&ex) | |
171 | {} | |
172 | #endif | |
173 | ||
174 | #if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED && ! defined BOOST_THREAD_PROVIDES_EXECUTORS | |
175 | task_region_handle_gen() | |
176 | : canceled(false) | |
177 | { | |
178 | } | |
179 | #endif | |
180 | ||
181 | ~task_region_handle_gen() | |
182 | { | |
183 | //wait_all(); | |
184 | } | |
185 | ||
186 | #if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED | |
187 | mutable mutex mtx; | |
188 | bool canceled; | |
189 | #endif | |
190 | #if defined BOOST_THREAD_PROVIDES_EXECUTORS | |
191 | Executor* ex; | |
192 | #endif | |
193 | exception_list exs; | |
194 | typedef csbl::vector<future<void> > group_type; | |
195 | group_type group; | |
196 | ||
197 | public: | |
198 | BOOST_DELETED_FUNCTION(task_region_handle_gen(const task_region_handle_gen&)) | |
199 | BOOST_DELETED_FUNCTION(task_region_handle_gen& operator=(const task_region_handle_gen&)) | |
200 | BOOST_DELETED_FUNCTION(task_region_handle_gen* operator&() const) | |
201 | ||
202 | public: | |
203 | template<typename F> | |
204 | void run(BOOST_THREAD_FWD_REF(F) f) | |
205 | { | |
206 | #if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED | |
207 | { | |
208 | lock_guard<mutex> lk(mtx); | |
209 | if (canceled) { | |
210 | boost::throw_exception(task_canceled_exception()); | |
211 | } | |
212 | } | |
213 | #if defined BOOST_THREAD_PROVIDES_EXECUTORS | |
214 | group.push_back(async(*ex, detail::wrapped<task_region_handle_gen<Executor>, F>(*this, forward<F>(f)))); | |
215 | #else | |
216 | group.push_back(async(detail::wrapped<task_region_handle_gen<Executor>, F>(*this, forward<F>(f)))); | |
217 | #endif | |
218 | #else | |
219 | #if defined BOOST_THREAD_PROVIDES_EXECUTORS | |
220 | group.push_back(async(*ex, forward<F>(f))); | |
221 | #else | |
222 | group.push_back(async(forward<F>(f))); | |
223 | #endif | |
224 | #endif | |
225 | } | |
226 | ||
227 | void wait() | |
228 | { | |
229 | #if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED | |
230 | { | |
231 | lock_guard<mutex> lk(mtx); | |
232 | if (canceled) { | |
233 | boost::throw_exception(task_canceled_exception()); | |
234 | } | |
235 | } | |
236 | #endif | |
237 | wait_all(); | |
238 | } | |
239 | }; | |
240 | #if defined BOOST_THREAD_PROVIDES_EXECUTORS | |
241 | typedef basic_thread_pool default_executor; | |
242 | #else | |
243 | typedef int default_executor; | |
244 | #endif | |
245 | class task_region_handle : | |
246 | public task_region_handle_gen<default_executor> | |
247 | { | |
248 | default_executor tp; | |
249 | template <typename F> | |
250 | friend void task_region(BOOST_THREAD_FWD_REF(F) f); | |
251 | template<typename F> | |
252 | friend void task_region_final(BOOST_THREAD_FWD_REF(F) f); | |
253 | ||
254 | protected: | |
255 | task_region_handle() : task_region_handle_gen<default_executor>() | |
256 | { | |
257 | #if defined BOOST_THREAD_PROVIDES_EXECUTORS | |
258 | ex = &tp; | |
259 | #endif | |
260 | } | |
261 | BOOST_DELETED_FUNCTION(task_region_handle(const task_region_handle&)) | |
262 | BOOST_DELETED_FUNCTION(task_region_handle& operator=(const task_region_handle&)) | |
263 | BOOST_DELETED_FUNCTION(task_region_handle* operator&() const) | |
264 | ||
265 | }; | |
266 | ||
267 | template <typename Executor, typename F> | |
268 | void task_region_final(Executor& ex, BOOST_THREAD_FWD_REF(F) f) | |
269 | { | |
270 | task_region_handle_gen<Executor> tr(ex); | |
271 | try | |
272 | { | |
273 | f(tr); | |
274 | } | |
275 | catch (...) | |
276 | { | |
277 | detail::handle_task_region_exceptions(tr.exs); | |
278 | } | |
279 | tr.wait_all(); | |
280 | } | |
281 | ||
282 | template <typename Executor, typename F> | |
283 | void task_region(Executor& ex, BOOST_THREAD_FWD_REF(F) f) | |
284 | { | |
285 | task_region_final(ex, forward<F>(f)); | |
286 | } | |
287 | ||
288 | template <typename F> | |
289 | void task_region_final(BOOST_THREAD_FWD_REF(F) f) | |
290 | { | |
291 | task_region_handle tr; | |
292 | try | |
293 | { | |
294 | f(tr); | |
295 | } | |
296 | catch (...) | |
297 | { | |
298 | detail::handle_task_region_exceptions(tr.exs); | |
299 | } | |
300 | tr.wait_all(); | |
301 | } | |
302 | ||
303 | template <typename F> | |
304 | void task_region(BOOST_THREAD_FWD_REF(F) f) | |
305 | { | |
306 | task_region_final(forward<F>(f)); | |
307 | } | |
308 | ||
309 | } // v2 | |
310 | } // parallel | |
311 | } // experimental | |
312 | } // boost | |
313 | ||
314 | #include <boost/config/abi_suffix.hpp> | |
315 | ||
316 | #endif // header |