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