task_group.h Source File

- Main Page
- Modules
- Namespaces
- Classes
- Files
- Related Pages

- File List
- File Members

# task_group.h

    00001 /*
    00002     Copyright 2005-2012 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-2012 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.