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