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