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     template<typename F>
00119     void run( task_handle<F>& h ) {
00120         internal_run< task_handle<F>, internal::task_handle_task<F> >( h );
00121     }
00122 
00123     task_group_status wait() {
00124         __TBB_TRY {
00125             my_root->wait_for_all();
00126         } __TBB_CATCH( ... ) {
00127             my_context.reset();
00128             __TBB_RETHROW();
00129         }
00130         if ( my_context.is_group_execution_cancelled() ) {
00131             my_context.reset();
00132             return canceled;
00133         }
00134         return complete;
00135     }
00136 
00137     bool is_canceling() {
00138         return my_context.is_group_execution_cancelled();
00139     }
00140 
00141     void cancel() {
00142         my_context.cancel_group_execution();
00143     }
00144 }; // class task_group_base
00145 
00146 } // namespace internal
00147 
00148 class task_group : public internal::task_group_base {
00149 public:
00150     task_group () : task_group_base( task_group_context::concurrent_wait ) {}
00151 
00152     ~task_group() __TBB_TRY {
00153         __TBB_ASSERT( my_root->ref_count() != 0, NULL );
00154         if( my_root->ref_count() > 1 )
00155             my_root->wait_for_all();
00156         owner().destroy(*my_root);
00157     }
00158 #if TBB_USE_EXCEPTIONS
00159     catch (...) {
00160         owner().destroy(*my_root);
00161         throw;
00162     }
00163 #endif /* TBB_USE_EXCEPTIONS */
00164 
00165 #if __SUNPRO_CC
00166     template<typename F>
00167     void run( task_handle<F>& h ) {
00168         internal_run< task_handle<F>, internal::task_handle_task<F> >( h );
00169     }
00170 #else
00171     using task_group_base::run;
00172 #endif
00173 
00174     template<typename F>
00175     void run( const F& f ) {
00176         internal_run< const F, internal::function_task<F> >( f );
00177     }
00178 
00179     template<typename F>
00180     task_group_status run_and_wait( const F& f ) {
00181         return internal_run_and_wait<const F>( f );
00182     }
00183 
00184     template<typename F>
00185     task_group_status run_and_wait( task_handle<F>& h ) {
00186       return internal_run_and_wait< task_handle<F> >( h );
00187     }
00188 }; // class task_group
00189 
00190 class structured_task_group : public internal::task_group_base {
00191 public:
00192     ~structured_task_group() {
00193         if( my_root->ref_count() > 1 ) {
00194             bool stack_unwinding_in_progress = std::uncaught_exception();
00195             // Always attempt to do proper cleanup to avoid inevitable memory corruption 
00196             // in case of missing wait (for the sake of better testability & debuggability)
00197             if ( !is_canceling() )
00198                 cancel();
00199             my_root->wait_for_all();
00200             owner().destroy(*my_root);
00201             if ( !stack_unwinding_in_progress )
00202                 internal::throw_exception( internal::eid_missing_wait );
00203         }
00204         else {
00205             if( my_root->ref_count() == 1 )
00206                 my_root->set_ref_count(0);
00207             owner().destroy(*my_root);
00208         }
00209     }
00210 
00211     template<typename F>
00212     task_group_status run_and_wait ( task_handle<F>& h ) {
00213         return internal_run_and_wait< task_handle<F> >( h );
00214     }
00215 
00216     task_group_status wait() {
00217         task_group_status res = task_group_base::wait();
00218         my_root->set_ref_count(1);
00219         return res;
00220     }
00221 }; // class structured_task_group
00222 
00223 inline 
00224 bool is_current_task_group_canceling() {
00225     return task::self().is_cancelled();
00226 }
00227 
00228 template<class F>
00229 task_handle<F> make_task( const F& f ) {
00230     return task_handle<F>( f );
00231 }
00232 
00233 } // namespace tbb
00234 
00235 #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.