00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #ifndef __TBB_task_group_H
00030 #define __TBB_task_group_H
00031
00032 #include "task.h"
00033 #include "tbb_exception.h"
00034
00035 #if __TBB_TASK_GROUP_CONTEXT
00036
00037 namespace tbb {
00038
00039 namespace internal {
00040 template<typename F> class task_handle_task;
00041 }
00042
00043 template<typename F>
00044 class task_handle : internal::no_assign {
00045 template<typename _F> friend class internal::task_handle_task;
00046
00047 static const intptr_t scheduled = 0x1;
00048
00049 F my_func;
00050 intptr_t my_state;
00051
00052 void mark_scheduled () {
00053
00054 if ( my_state & scheduled )
00055 internal::throw_exception( internal::eid_invalid_multiple_scheduling );
00056 my_state |= scheduled;
00057 }
00058 public:
00059 task_handle( const F& f ) : my_func(f), my_state(0) {}
00060
00061 void operator() () const { my_func(); }
00062 };
00063
00064 enum task_group_status {
00065 not_complete,
00066 complete,
00067 canceled
00068 };
00069
00070 namespace internal {
00071
00072
00073
00074
00075 template<typename F>
00076 class function_task : public task {
00077 F my_func;
00078 task* execute() {
00079 my_func();
00080 return NULL;
00081 }
00082 public:
00083 function_task( const F& f ) : my_func(f) {}
00084 };
00085
00086 template<typename F>
00087 class task_handle_task : public task {
00088 task_handle<F>& my_handle;
00089 task* execute() {
00090 my_handle();
00091 return NULL;
00092 }
00093 public:
00094 task_handle_task( task_handle<F>& h ) : my_handle(h) { h.mark_scheduled(); }
00095 };
00096
00097 class task_group_base : internal::no_copy {
00098 protected:
00099 empty_task* my_root;
00100 task_group_context my_context;
00101
00102 task& owner () { return *my_root; }
00103
00104 template<typename F>
00105 task_group_status internal_run_and_wait( F& f ) {
00106 __TBB_TRY {
00107 if ( !my_context.is_group_execution_cancelled() )
00108 f();
00109 } __TBB_CATCH( ... ) {
00110 my_context.register_pending_exception();
00111 }
00112 return wait();
00113 }
00114
00115 template<typename F, typename Task>
00116 void internal_run( F& f ) {
00117 owner().spawn( *new( owner().allocate_additional_child_of(*my_root) ) Task(f) );
00118 }
00119
00120 public:
00121 task_group_base( uintptr_t traits = 0 )
00122 : my_context(task_group_context::bound, task_group_context::default_traits | traits)
00123 {
00124 my_root = new( task::allocate_root(my_context) ) empty_task;
00125 my_root->set_ref_count(1);
00126 }
00127
00128 ~task_group_base() {
00129 if( my_root->ref_count() > 1 ) {
00130 bool stack_unwinding_in_progress = std::uncaught_exception();
00131
00132
00133 if ( !is_canceling() )
00134 cancel();
00135 __TBB_TRY {
00136 my_root->wait_for_all();
00137 } __TBB_CATCH (...) {
00138 task::destroy(*my_root);
00139 __TBB_RETHROW();
00140 }
00141 task::destroy(*my_root);
00142 if ( !stack_unwinding_in_progress )
00143 internal::throw_exception( internal::eid_missing_wait );
00144 }
00145 else {
00146 task::destroy(*my_root);
00147 }
00148 }
00149
00150 template<typename F>
00151 void run( task_handle<F>& h ) {
00152 internal_run< task_handle<F>, internal::task_handle_task<F> >( h );
00153 }
00154
00155 task_group_status wait() {
00156 __TBB_TRY {
00157 my_root->wait_for_all();
00158 } __TBB_CATCH( ... ) {
00159 my_context.reset();
00160 __TBB_RETHROW();
00161 }
00162 if ( my_context.is_group_execution_cancelled() ) {
00163 my_context.reset();
00164 return canceled;
00165 }
00166 return complete;
00167 }
00168
00169 bool is_canceling() {
00170 return my_context.is_group_execution_cancelled();
00171 }
00172
00173 void cancel() {
00174 my_context.cancel_group_execution();
00175 }
00176 };
00177
00178 }
00179
00180 class task_group : public internal::task_group_base {
00181 public:
00182 task_group () : task_group_base( task_group_context::concurrent_wait ) {}
00183
00184 #if TBB_DEPRECATED
00185 ~task_group() __TBB_TRY {
00186 __TBB_ASSERT( my_root->ref_count() != 0, NULL );
00187 if( my_root->ref_count() > 1 )
00188 my_root->wait_for_all();
00189 }
00190 #if TBB_USE_EXCEPTIONS
00191 catch (...) {
00192
00193 task::destroy(*my_root);
00194 throw;
00195 }
00196 #endif
00197 #endif
00198
00199 #if __SUNPRO_CC
00200 template<typename F>
00201 void run( task_handle<F>& h ) {
00202 internal_run< task_handle<F>, internal::task_handle_task<F> >( h );
00203 }
00204 #else
00205 using task_group_base::run;
00206 #endif
00207
00208 template<typename F>
00209 void run( const F& f ) {
00210 internal_run< const F, internal::function_task<F> >( f );
00211 }
00212
00213 template<typename F>
00214 task_group_status run_and_wait( const F& f ) {
00215 return internal_run_and_wait<const F>( f );
00216 }
00217
00218 template<typename F>
00219 task_group_status run_and_wait( task_handle<F>& h ) {
00220 return internal_run_and_wait< task_handle<F> >( h );
00221 }
00222 };
00223
00224 class structured_task_group : public internal::task_group_base {
00225 public:
00226 template<typename F>
00227 task_group_status run_and_wait ( task_handle<F>& h ) {
00228 return internal_run_and_wait< task_handle<F> >( h );
00229 }
00230
00231 task_group_status wait() {
00232 task_group_status res = task_group_base::wait();
00233 my_root->set_ref_count(1);
00234 return res;
00235 }
00236 };
00237
00238 inline
00239 bool is_current_task_group_canceling() {
00240 return task::self().is_cancelled();
00241 }
00242
00243 template<class F>
00244 task_handle<F> make_task( const F& f ) {
00245 return task_handle<F>( f );
00246 }
00247
00248 }
00249
00250 #endif
00251
00252 #endif