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