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