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