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