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 using task_group_base::run;
00152
00153 template<typename F>
00154 void run( const F& f ) {
00155 internal_run< const F, internal::function_task<F> >( f );
00156 }
00157
00158 template<typename F>
00159 task_group_status run_and_wait( const F& f ) {
00160 return internal_run_and_wait<const F>( f );
00161 }
00162
00163 template<typename F>
00164 task_group_status run_and_wait( F& f ) {
00165 return internal_run_and_wait<F>( f );
00166 }
00167
00168 };
00169
00170 class missing_wait : public std::exception {
00171 public:
00172
00173 const char* what() const throw() { return "wait() was not called on the structured_task_group"; }
00174 };
00175
00176 class structured_task_group : public internal::task_group_base {
00177 public:
00178 ~structured_task_group() {
00179 if( my_root->ref_count() > 1 ) {
00180 bool stack_unwinding_in_progress = std::uncaught_exception();
00181
00182
00183 if ( !is_canceling() )
00184 cancel();
00185 my_root->wait_for_all();
00186 owner().destroy(*my_root);
00187 if ( !stack_unwinding_in_progress )
00188 throw missing_wait();
00189 }
00190 else
00191 owner().destroy(*my_root);
00192 }
00193
00194 template<typename F>
00195 task_group_status run_and_wait ( task_handle<F>& h ) {
00196 return internal_run_and_wait< task_handle<F> >( h );
00197 }
00198
00199 task_group_status wait() {
00200 __TBB_ASSERT ( my_root->ref_count() != 0, "wait() can be called only once during the structured_task_group lifetime" );
00201 return task_group_base::wait();
00202 }
00203 };
00204
00205 inline
00206 bool is_current_task_group_canceling() {
00207 return task::self().is_cancelled();
00208 }
00209
00210 }
00211
00212 #endif