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 template<typename F>
00119 void run( task_handle<F>& h ) {
00120 internal_run< task_handle<F>, internal::task_handle_task<F> >( h );
00121 }
00122
00123 task_group_status wait() {
00124 __TBB_TRY {
00125 my_root->wait_for_all();
00126 } __TBB_CATCH( ... ) {
00127 my_context.reset();
00128 __TBB_RETHROW();
00129 }
00130 if ( my_context.is_group_execution_cancelled() ) {
00131 my_context.reset();
00132 return canceled;
00133 }
00134 return complete;
00135 }
00136
00137 bool is_canceling() {
00138 return my_context.is_group_execution_cancelled();
00139 }
00140
00141 void cancel() {
00142 my_context.cancel_group_execution();
00143 }
00144 };
00145
00146 }
00147
00148 class task_group : public internal::task_group_base {
00149 public:
00150 task_group () : task_group_base( task_group_context::concurrent_wait ) {}
00151
00152 ~task_group() __TBB_TRY {
00153 __TBB_ASSERT( my_root->ref_count() != 0, NULL );
00154 if( my_root->ref_count() > 1 )
00155 my_root->wait_for_all();
00156 owner().destroy(*my_root);
00157 }
00158 #if TBB_USE_EXCEPTIONS
00159 catch (...) {
00160 owner().destroy(*my_root);
00161 throw;
00162 }
00163 #endif
00164
00165 #if __SUNPRO_CC
00166 template<typename F>
00167 void run( task_handle<F>& h ) {
00168 internal_run< task_handle<F>, internal::task_handle_task<F> >( h );
00169 }
00170 #else
00171 using task_group_base::run;
00172 #endif
00173
00174 template<typename F>
00175 void run( const F& f ) {
00176 internal_run< const F, internal::function_task<F> >( f );
00177 }
00178
00179 template<typename F>
00180 task_group_status run_and_wait( const F& f ) {
00181 return internal_run_and_wait<const F>( f );
00182 }
00183
00184 template<typename F>
00185 task_group_status run_and_wait( task_handle<F>& h ) {
00186 return internal_run_and_wait< task_handle<F> >( h );
00187 }
00188 };
00189
00190 class structured_task_group : public internal::task_group_base {
00191 public:
00192 ~structured_task_group() {
00193 if( my_root->ref_count() > 1 ) {
00194 bool stack_unwinding_in_progress = std::uncaught_exception();
00195
00196
00197 if ( !is_canceling() )
00198 cancel();
00199 my_root->wait_for_all();
00200 owner().destroy(*my_root);
00201 if ( !stack_unwinding_in_progress )
00202 internal::throw_exception( internal::eid_missing_wait );
00203 }
00204 else {
00205 if( my_root->ref_count() == 1 )
00206 my_root->set_ref_count(0);
00207 owner().destroy(*my_root);
00208 }
00209 }
00210
00211 template<typename F>
00212 task_group_status run_and_wait ( task_handle<F>& h ) {
00213 return internal_run_and_wait< task_handle<F> >( h );
00214 }
00215
00216 task_group_status wait() {
00217 task_group_status res = task_group_base::wait();
00218 my_root->set_ref_count(1);
00219 return res;
00220 }
00221 };
00222
00223 inline
00224 bool is_current_task_group_canceling() {
00225 return task::self().is_cancelled();
00226 }
00227
00228 template<class F>
00229 task_handle<F> make_task( const F& f ) {
00230 return task_handle<F>( f );
00231 }
00232
00233 }
00234
00235 #endif