task_group.h

00001 /*
00002     Copyright 2005-2011 Intel Corporation.  All Rights Reserved.
00003 
00004     The source code contained or described herein and all documents related
00005     to the source code ("Material") are owned by Intel Corporation or its
00006     suppliers or licensors.  Title to the Material remains with Intel
00007     Corporation or its suppliers and licensors.  The Material is protected
00008     by worldwide copyright laws and treaty provisions.  No part of the
00009     Material may be used, copied, reproduced, modified, published, uploaded,
00010     posted, transmitted, distributed, or disclosed in any way without
00011     Intel's prior express written permission.
00012 
00013     No license under any patent, copyright, trade secret or other
00014     intellectual property right is granted to or conferred upon you by
00015     disclosure or delivery of the Materials, either expressly, by
00016     implication, inducement, estoppel or otherwise.  Any license under such
00017     intellectual property rights must be express and approved by Intel in
00018     writing.
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 #if __TBB_TASK_GROUP_CONTEXT
00028 
00029 namespace tbb {
00030 
00031 namespace internal {
00032     template<typename F> class task_handle_task;
00033 }
00034 
00035 template<typename F>
00036 class task_handle : internal::no_assign {
00037     template<typename _F> friend class internal::task_handle_task;
00038 
00039     static const intptr_t scheduled = 0x1;
00040 
00041     F my_func;
00042     intptr_t my_state;
00043 
00044     void mark_scheduled () {
00045         // The check here is intentionally lax to avoid the impact of interlocked operation
00046         if ( my_state & scheduled )
00047             internal::throw_exception( internal::eid_invalid_multiple_scheduling );
00048         my_state |= scheduled;
00049     }
00050 public:
00051     task_handle( const F& f ) : my_func(f), my_state(0) {}
00052 
00053     void operator() () const { my_func(); }
00054 };
00055 
00056 enum task_group_status {
00057     not_complete,
00058     complete,
00059     canceled
00060 };
00061 
00062 namespace internal {
00063 
00064 // Suppress gratuitous warnings from icc 11.0 when lambda expressions are used in instances of function_task.
00065 //#pragma warning(disable: 588)
00066 
00067 template<typename F>
00068 class function_task : public task {
00069     F my_func;
00070     /*override*/ task* execute() {
00071         my_func();
00072         return NULL;
00073     }
00074 public:
00075     function_task( const F& f ) : my_func(f) {}
00076 };
00077 
00078 template<typename F>
00079 class task_handle_task : public task {
00080     task_handle<F>& my_handle;
00081     /*override*/ task* execute() {
00082         my_handle();
00083         return NULL;
00084     }
00085 public:
00086     task_handle_task( task_handle<F>& h ) : my_handle(h) { h.mark_scheduled(); }
00087 };
00088 
00089 class task_group_base : internal::no_copy {
00090 protected:
00091     empty_task* my_root;
00092     task_group_context my_context;
00093 
00094     task& owner () { return *my_root; }
00095 
00096     template<typename F>
00097     task_group_status internal_run_and_wait( F& f ) {
00098         __TBB_TRY {
00099             if ( !my_context.is_group_execution_cancelled() )
00100                 f();
00101         } __TBB_CATCH( ... ) {
00102             my_context.register_pending_exception();
00103         }
00104         return wait();
00105     }
00106 
00107     template<typename F, typename Task>
00108     void internal_run( F& f ) {
00109         owner().spawn( *new( owner().allocate_additional_child_of(*my_root) ) Task(f) );
00110     }
00111 
00112 public:
00113     task_group_base( uintptr_t traits = 0 )
00114         : my_context(task_group_context::bound, task_group_context::default_traits | traits)
00115     {
00116         my_root = new( task::allocate_root(my_context) ) empty_task;
00117         my_root->set_ref_count(1);
00118     }
00119 
00120     ~task_group_base() {
00121         if( my_root->ref_count() > 1 ) {
00122             bool stack_unwinding_in_progress = std::uncaught_exception();
00123             // Always attempt to do proper cleanup to avoid inevitable memory corruption 
00124             // in case of missing wait (for the sake of better testability & debuggability)
00125             if ( !is_canceling() )
00126                 cancel();
00127             __TBB_TRY {
00128                 my_root->wait_for_all();
00129             } __TBB_CATCH (...) {
00130                 task::destroy(*my_root);
00131                 __TBB_RETHROW();
00132             }
00133             task::destroy(*my_root);
00134             if ( !stack_unwinding_in_progress )
00135                 internal::throw_exception( internal::eid_missing_wait );
00136         }
00137         else {
00138             task::destroy(*my_root);
00139         }
00140     }
00141 
00142     template<typename F>
00143     void run( task_handle<F>& h ) {
00144         internal_run< task_handle<F>, internal::task_handle_task<F> >( h );
00145     }
00146 
00147     task_group_status wait() {
00148         __TBB_TRY {
00149             my_root->wait_for_all();
00150         } __TBB_CATCH( ... ) {
00151             my_context.reset();
00152             __TBB_RETHROW();
00153         }
00154         if ( my_context.is_group_execution_cancelled() ) {
00155             my_context.reset();
00156             return canceled;
00157         }
00158         return complete;
00159     }
00160 
00161     bool is_canceling() {
00162         return my_context.is_group_execution_cancelled();
00163     }
00164 
00165     void cancel() {
00166         my_context.cancel_group_execution();
00167     }
00168 }; // class task_group_base
00169 
00170 } // namespace internal
00171 
00172 class task_group : public internal::task_group_base {
00173 public:
00174     task_group () : task_group_base( task_group_context::concurrent_wait ) {}
00175 
00176 #if TBB_DEPRECATED
00177     ~task_group() __TBB_TRY {
00178         __TBB_ASSERT( my_root->ref_count() != 0, NULL );
00179         if( my_root->ref_count() > 1 )
00180             my_root->wait_for_all();
00181     }
00182 #if TBB_USE_EXCEPTIONS
00183     catch (...) {
00184         // Have to destroy my_root here as the base class destructor won't be called
00185         task::destroy(*my_root);
00186         throw;
00187     }
00188 #endif /* TBB_USE_EXCEPTIONS */
00189 #endif /* TBB_DEPRECATED */
00190 
00191 #if __SUNPRO_CC
00192     template<typename F>
00193     void run( task_handle<F>& h ) {
00194         internal_run< task_handle<F>, internal::task_handle_task<F> >( h );
00195     }
00196 #else
00197     using task_group_base::run;
00198 #endif
00199 
00200     template<typename F>
00201     void run( const F& f ) {
00202         internal_run< const F, internal::function_task<F> >( f );
00203     }
00204 
00205     template<typename F>
00206     task_group_status run_and_wait( const F& f ) {
00207         return internal_run_and_wait<const F>( f );
00208     }
00209 
00210     template<typename F>
00211     task_group_status run_and_wait( task_handle<F>& h ) {
00212       return internal_run_and_wait< task_handle<F> >( h );
00213     }
00214 }; // class task_group
00215 
00216 class structured_task_group : public internal::task_group_base {
00217 public:
00218     template<typename F>
00219     task_group_status run_and_wait ( task_handle<F>& h ) {
00220         return internal_run_and_wait< task_handle<F> >( h );
00221     }
00222 
00223     task_group_status wait() {
00224         task_group_status res = task_group_base::wait();
00225         my_root->set_ref_count(1);
00226         return res;
00227     }
00228 }; // class structured_task_group
00229 
00230 inline 
00231 bool is_current_task_group_canceling() {
00232     return task::self().is_cancelled();
00233 }
00234 
00235 template<class F>
00236 task_handle<F> make_task( const F& f ) {
00237     return task_handle<F>( f );
00238 }
00239 
00240 } // namespace tbb
00241 
00242 #endif /* __TBB_TASK_GROUP_CONTEXT */
00243 
00244 #endif /* __TBB_task_group_H */

Copyright © 2005-2011 Intel Corporation. All Rights Reserved.

Intel, Pentium, Intel Xeon, Itanium, Intel XScale and VTune are registered trademarks or trademarks of Intel Corporation or its subsidiaries in the United States and other countries.

* Other names and brands may be claimed as the property of others.