BRE12
task_group.h
1 /*
2  Copyright 2005-2016 Intel Corporation. All Rights Reserved.
3 
4  This file is part of Threading Building Blocks. Threading Building Blocks is free software;
5  you can redistribute it and/or modify it under the terms of the GNU General Public License
6  version 2 as published by the Free Software Foundation. Threading Building Blocks is
7  distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
8  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
9  See the GNU General Public License for more details. You should have received a copy of
10  the GNU General Public License along with Threading Building Blocks; if not, write to the
11  Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
12 
13  As a special exception, you may use this file as part of a free software library without
14  restriction. Specifically, if other files instantiate templates or use macros or inline
15  functions from this file, or you compile this file and link it with other files to produce
16  an executable, this file does not by itself cause the resulting executable to be covered
17  by the GNU General Public License. This exception does not however invalidate any other
18  reasons why the executable file might be covered by the GNU General Public License.
19 */
20 
21 #ifndef __TBB_task_group_H
22 #define __TBB_task_group_H
23 
24 #include "task.h"
25 #include "tbb_exception.h"
26 
27 #if __TBB_TASK_GROUP_CONTEXT
28 
29 namespace tbb {
30 
31 namespace internal {
32  template<typename F> class task_handle_task;
33 }
34 
35 class task_group;
37 
38 template<typename F>
39 class task_handle : internal::no_assign {
40  template<typename _F> friend class internal::task_handle_task;
41  friend class task_group;
42  friend class structured_task_group;
43 
44  static const intptr_t scheduled = 0x1;
45 
46  F my_func;
47  intptr_t my_state;
48 
49  void mark_scheduled () {
50  // The check here is intentionally lax to avoid the impact of interlocked operation
51  if ( my_state & scheduled )
52  internal::throw_exception( internal::eid_invalid_multiple_scheduling );
53  my_state |= scheduled;
54  }
55 public:
56  task_handle( const F& f ) : my_func(f), my_state(0) {}
57 
58  void operator() () const { my_func(); }
59 };
60 
61 enum task_group_status {
62  not_complete,
63  complete,
64  canceled
65 };
66 
67 namespace internal {
68 
69 template<typename F>
70 class task_handle_task : public task {
71  task_handle<F>& my_handle;
72  /*override*/ task* execute() {
73  my_handle();
74  return NULL;
75  }
76 public:
77  task_handle_task( task_handle<F>& h ) : my_handle(h) { h.mark_scheduled(); }
78 };
79 
80 class task_group_base : internal::no_copy {
81 protected:
82  empty_task* my_root;
83  task_group_context my_context;
84 
85  task& owner () { return *my_root; }
86 
87  template<typename F>
88  task_group_status internal_run_and_wait( F& f ) {
89  __TBB_TRY {
90  if ( !my_context.is_group_execution_cancelled() )
91  f();
92  } __TBB_CATCH( ... ) {
93  my_context.register_pending_exception();
94  }
95  return wait();
96  }
97 
98  template<typename F, typename Task>
99  void internal_run( F& f ) {
100  owner().spawn( *new( owner().allocate_additional_child_of(*my_root) ) Task(f) );
101  }
102 
103 public:
104  task_group_base( uintptr_t traits = 0 )
105  : my_context(task_group_context::bound, task_group_context::default_traits | traits)
106  {
107  my_root = new( task::allocate_root(my_context) ) empty_task;
108  my_root->set_ref_count(1);
109  }
110 
111  ~task_group_base() __TBB_NOEXCEPT(false) {
112  if( my_root->ref_count() > 1 ) {
113  bool stack_unwinding_in_progress = std::uncaught_exception();
114  // Always attempt to do proper cleanup to avoid inevitable memory corruption
115  // in case of missing wait (for the sake of better testability & debuggability)
116  if ( !is_canceling() )
117  cancel();
118  __TBB_TRY {
119  my_root->wait_for_all();
120  } __TBB_CATCH (...) {
121  task::destroy(*my_root);
122  __TBB_RETHROW();
123  }
124  task::destroy(*my_root);
125  if ( !stack_unwinding_in_progress )
126  internal::throw_exception( internal::eid_missing_wait );
127  }
128  else {
129  task::destroy(*my_root);
130  }
131  }
132 
133  template<typename F>
134  void run( task_handle<F>& h ) {
135  internal_run< task_handle<F>, internal::task_handle_task<F> >( h );
136  }
137 
138  task_group_status wait() {
139  __TBB_TRY {
140  my_root->wait_for_all();
141  } __TBB_CATCH( ... ) {
142  my_context.reset();
143  __TBB_RETHROW();
144  }
145  if ( my_context.is_group_execution_cancelled() ) {
146  // TODO: the reset method is not thread-safe. Ensure the correct behavior.
147  my_context.reset();
148  return canceled;
149  }
150  return complete;
151  }
152 
153  bool is_canceling() {
154  return my_context.is_group_execution_cancelled();
155  }
156 
157  void cancel() {
158  my_context.cancel_group_execution();
159  }
160 }; // class task_group_base
161 
162 } // namespace internal
163 
165 public:
166  task_group () : task_group_base( task_group_context::concurrent_wait ) {}
167 
168 #if __SUNPRO_CC
169  template<typename F>
170  void run( task_handle<F>& h ) {
171  internal_run< task_handle<F>, internal::task_handle_task<F> >( h );
172  }
173 #else
174  using task_group_base::run;
175 #endif
176 
177  template<typename F>
178  void run( const F& f ) {
179  internal_run< const F, internal::function_task<F> >( f );
180  }
181 
182  template<typename F>
183  task_group_status run_and_wait( const F& f ) {
184  return internal_run_and_wait<const F>( f );
185  }
186 
187  template<typename F>
188  task_group_status run_and_wait( task_handle<F>& h ) {
189  h.mark_scheduled();
190  return internal_run_and_wait< task_handle<F> >( h );
191  }
192 }; // class task_group
193 
195 public:
196  template<typename F>
197  task_group_status run_and_wait ( task_handle<F>& h ) {
198  h.mark_scheduled();
199  return internal_run_and_wait< task_handle<F> >( h );
200  }
201 
202  task_group_status wait() {
203  task_group_status res = task_group_base::wait();
204  my_root->set_ref_count(1);
205  return res;
206  }
207 }; // class structured_task_group
208 
209 inline
210 bool is_current_task_group_canceling() {
211  return task::self().is_cancelled();
212 }
213 
214 template<class F>
215 task_handle<F> make_task( const F& f ) {
216  return task_handle<F>( f );
217 }
218 
219 } // namespace tbb
220 
221 #endif /* __TBB_TASK_GROUP_CONTEXT */
222 
223 #endif /* __TBB_task_group_H */
Definition: task_group.h:194
Definition: task_group.h:164
Definition: task_group.h:80
Definition: task_group.h:32
Definition: task_group.h:39
Definition: _flow_graph_async_msg_impl.h:32
The namespace tbb contains all components of the library.
Definition: parallel_for.h:44