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