task_group.h Source File

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

- File List
- File Members

# 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.