task_group.h

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

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