task_group.h

00001 /*
00002     Copyright 2005-2010 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 namespace tbb {
00028 
00029 namespace internal {
00030     template<typename F> class task_handle_task;
00031 }
00032 
00033 template<typename F>
00034 class task_handle : internal::no_assign {
00035     template<typename _F> friend class internal::task_handle_task;
00036 
00037     static const intptr_t scheduled = 0x1;
00038 
00039     F my_func;
00040     intptr_t my_state;
00041 
00042     void mark_scheduled () {
00043         // The check here is intentionally lax to avoid the impact of interlocked operation
00044         if ( my_state & scheduled )
00045             internal::throw_exception( internal::eid_invalid_multiple_scheduling );
00046         my_state |= scheduled;
00047     }
00048 public:
00049     task_handle( const F& f ) : my_func(f), my_state(0) {}
00050 
00051     void operator() () const { my_func(); }
00052 };
00053 
00054 enum task_group_status {
00055     not_complete,
00056     complete,
00057     canceled
00058 };
00059 
00060 namespace internal {
00061 
00062 // Suppress gratuitous warnings from icc 11.0 when lambda expressions are used in instances of function_task.
00063 //#pragma warning(disable: 588)
00064 
00065 template<typename F>
00066 class function_task : public task {
00067     F my_func;
00068     /*override*/ task* execute() {
00069         my_func();
00070         return NULL;
00071     }
00072 public:
00073     function_task( const F& f ) : my_func(f) {}
00074 };
00075 
00076 template<typename F>
00077 class task_handle_task : public task {
00078     task_handle<F>& my_handle;
00079     /*override*/ task* execute() {
00080         my_handle();
00081         return NULL;
00082     }
00083 public:
00084     task_handle_task( task_handle<F>& h ) : my_handle(h) { h.mark_scheduled(); }
00085 };
00086 
00087 class task_group_base : internal::no_copy {
00088 protected:
00089     empty_task* my_root;
00090     task_group_context my_context;
00091 
00092     task& owner () { return *my_root; }
00093 
00094     template<typename F>
00095     task_group_status internal_run_and_wait( F& f ) {
00096         __TBB_TRY {
00097             if ( !my_context.is_group_execution_cancelled() )
00098                 f();
00099         } __TBB_CATCH( ... ) {
00100             my_context.register_pending_exception();
00101         }
00102         return wait();
00103     }
00104 
00105     template<typename F, typename Task>
00106     void internal_run( F& f ) {
00107         owner().spawn( *new( owner().allocate_additional_child_of(*my_root) ) Task(f) );
00108     }
00109 
00110 public:
00111     task_group_base( uintptr_t traits = 0 )
00112         : my_context(task_group_context::bound, task_group_context::default_traits | traits)
00113     {
00114         my_root = new( task::allocate_root(my_context) ) empty_task;
00115         my_root->set_ref_count(1);
00116     }
00117 
00118     ~task_group_base() {
00119         if( my_root->ref_count() > 1 ) {
00120             bool stack_unwinding_in_progress = std::uncaught_exception();
00121             // Always attempt to do proper cleanup to avoid inevitable memory corruption 
00122             // in case of missing wait (for the sake of better testability & debuggability)
00123             if ( !is_canceling() )
00124                 cancel();
00125             __TBB_TRY {
00126                 my_root->wait_for_all();
00127             } __TBB_CATCH (...) {
00128                 task::destroy(*my_root);
00129                 __TBB_RETHROW();
00130             }
00131             task::destroy(*my_root);
00132             if ( !stack_unwinding_in_progress )
00133                 internal::throw_exception( internal::eid_missing_wait );
00134         }
00135         else {
00136             task::destroy(*my_root);
00137         }
00138     }
00139 
00140     template<typename F>
00141     void run( task_handle<F>& h ) {
00142         internal_run< task_handle<F>, internal::task_handle_task<F> >( h );
00143     }
00144 
00145     task_group_status wait() {
00146         __TBB_TRY {
00147             my_root->wait_for_all();
00148         } __TBB_CATCH( ... ) {
00149             my_context.reset();
00150             __TBB_RETHROW();
00151         }
00152         if ( my_context.is_group_execution_cancelled() ) {
00153             my_context.reset();
00154             return canceled;
00155         }
00156         return complete;
00157     }
00158 
00159     bool is_canceling() {
00160         return my_context.is_group_execution_cancelled();
00161     }
00162 
00163     void cancel() {
00164         my_context.cancel_group_execution();
00165     }
00166 }; // class task_group_base
00167 
00168 } // namespace internal
00169 
00170 class task_group : public internal::task_group_base {
00171 public:
00172     task_group () : task_group_base( task_group_context::concurrent_wait ) {}
00173 
00174 #if TBB_DEPRECATED
00175     ~task_group() __TBB_TRY {
00176         __TBB_ASSERT( my_root->ref_count() != 0, NULL );
00177         if( my_root->ref_count() > 1 )
00178             my_root->wait_for_all();
00179     }
00180 #if TBB_USE_EXCEPTIONS
00181     catch (...) {
00182         // Have to destroy my_root here as the base class destructor won't be called
00183         task::destroy(*my_root);
00184         throw;
00185     }
00186 #endif /* TBB_USE_EXCEPTIONS */
00187 #endif /* TBB_DEPRECATED */
00188 
00189 #if __SUNPRO_CC
00190     template<typename F>
00191     void run( task_handle<F>& h ) {
00192         internal_run< task_handle<F>, internal::task_handle_task<F> >( h );
00193     }
00194 #else
00195     using task_group_base::run;
00196 #endif
00197 
00198     template<typename F>
00199     void run( const F& f ) {
00200         internal_run< const F, internal::function_task<F> >( f );
00201     }
00202 
00203     template<typename F>
00204     task_group_status run_and_wait( const F& f ) {
00205         return internal_run_and_wait<const F>( f );
00206     }
00207 
00208     template<typename F>
00209     task_group_status run_and_wait( task_handle<F>& h ) {
00210       return internal_run_and_wait< task_handle<F> >( h );
00211     }
00212 }; // class task_group
00213 
00214 class structured_task_group : public internal::task_group_base {
00215 public:
00216     template<typename F>
00217     task_group_status run_and_wait ( task_handle<F>& h ) {
00218         return internal_run_and_wait< task_handle<F> >( h );
00219     }
00220 
00221     task_group_status wait() {
00222         task_group_status res = task_group_base::wait();
00223         my_root->set_ref_count(1);
00224         return res;
00225     }
00226 }; // class structured_task_group
00227 
00228 inline 
00229 bool is_current_task_group_canceling() {
00230     return task::self().is_cancelled();
00231 }
00232 
00233 template<class F>
00234 task_handle<F> make_task( const F& f ) {
00235     return task_handle<F>( f );
00236 }
00237 
00238 } // namespace tbb
00239 
00240 #endif /* __TBB_task_group_H */

Copyright © 2005-2010 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.