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

- File List
- File Members

# task_group.h

    00001 /*
    00002     Copyright 2005-2012 Intel Corporation.  All Rights Reserved.
    00003
    00004     This file is part of Threading Building Blocks.
    00005
    00006     Threading Building Blocks is free software; you can redistribute it
    00007     and/or modify it under the terms of the GNU General Public License
    00008     version 2 as published by the Free Software Foundation.
    00009
    00010     Threading Building Blocks is distributed in the hope that it will be
    00011     useful, but WITHOUT ANY WARRANTY; without even the implied warranty
    00012     of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    00013     GNU General Public License for more details.
    00014
    00015     You should have received a copy of the GNU General Public License
    00016     along with Threading Building Blocks; if not, write to the Free Software
    00017     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    00018
    00019     As a special exception, you may use this file as part of a free software
    00020     library without restriction.  Specifically, if other files instantiate
    00021     templates or use macros or inline functions from this file, or you compile
    00022     this file and link it with other files to produce an executable, this
    00023     file does not by itself cause the resulting executable to be covered by
    00024     the GNU General Public License.  This exception does not however
    00025     invalidate any other reasons why the executable file might be covered by
    00026     the GNU General Public License.
    00027 */
    00028
    00029 #ifndef __TBB_task_group_H
    00030 #define __TBB_task_group_H
    00031
    00032 #include "task.h"
    00033 #include "tbb_exception.h"
    00034
    00035 #if __TBB_TASK_GROUP_CONTEXT
    00036
    00037 namespace tbb {
    00038
    00039 namespace internal {
    00040     template<typename F> class task_handle_task;
    00041 }
    00042
    00043 template<typename F>
    00044 class task_handle : internal::no_assign {
    00045     template<typename _F> friend class internal::task_handle_task;
    00046
    00047     static const intptr_t scheduled = 0x1;
    00048
    00049     F my_func;
    00050     intptr_t my_state;
    00051
    00052     void mark_scheduled () {
    00053         // The check here is intentionally lax to avoid the impact of interlocked operation
    00054         if ( my_state & scheduled )
    00055             internal::throw_exception( internal::eid_invalid_multiple_scheduling );
    00056         my_state |= scheduled;
    00057     }
    00058 public:
    00059     task_handle( const F& f ) : my_func(f), my_state(0) {}
    00060
    00061     void operator() () const { my_func(); }
    00062 };
    00063
    00064 enum task_group_status {
    00065     not_complete,
    00066     complete,
    00067     canceled
    00068 };
    00069
    00070 namespace internal {
    00071
    00072 // Suppress gratuitous warnings from icc 11.0 when lambda expressions are used in instances of function_task.
    00073 //#pragma warning(disable: 588)
    00074
    00075 template<typename F>
    00076 class function_task : public task {
    00077     F my_func;
    00078     /*override*/ task* execute() {
    00079         my_func();
    00080         return NULL;
    00081     }
    00082 public:
    00083     function_task( const F& f ) : my_func(f) {}
    00084 };
    00085
    00086 template<typename F>
    00087 class task_handle_task : public task {
    00088     task_handle<F>& my_handle;
    00089     /*override*/ task* execute() {
    00090         my_handle();
    00091         return NULL;
    00092     }
    00093 public:
    00094     task_handle_task( task_handle<F>& h ) : my_handle(h) { h.mark_scheduled(); }
    00095 };
    00096
    00097 class task_group_base : internal::no_copy {
    00098 protected:
    00099     empty_task* my_root;
    00100     task_group_context my_context;
    00101
    00102     task& owner () { return *my_root; }
    00103
    00104     template<typename F>
    00105     task_group_status internal_run_and_wait( F& f ) {
    00106         __TBB_TRY {
    00107             if ( !my_context.is_group_execution_cancelled() )
    00108                 f();
    00109         } __TBB_CATCH( ... ) {
    00110             my_context.register_pending_exception();
    00111         }
    00112         return wait();
    00113     }
    00114
    00115     template<typename F, typename Task>
    00116     void internal_run( F& f ) {
    00117         owner().spawn( *new( owner().allocate_additional_child_of(*my_root) ) Task(f) );
    00118     }
    00119
    00120 public:
    00121     task_group_base( uintptr_t traits = 0 )
    00122         : my_context(task_group_context::bound, task_group_context::default_traits | traits)
    00123     {
    00124         my_root = new( task::allocate_root(my_context) ) empty_task;
    00125         my_root->set_ref_count(1);
    00126     }
    00127
    00128     ~task_group_base() {
    00129         if( my_root->ref_count() > 1 ) {
    00130             bool stack_unwinding_in_progress = std::uncaught_exception();
    00131             // Always attempt to do proper cleanup to avoid inevitable memory corruption
    00132             // in case of missing wait (for the sake of better testability & debuggability)
    00133             if ( !is_canceling() )
    00134                 cancel();
    00135             __TBB_TRY {
    00136                 my_root->wait_for_all();
    00137             } __TBB_CATCH (...) {
    00138                 task::destroy(*my_root);
    00139                 __TBB_RETHROW();
    00140             }
    00141             task::destroy(*my_root);
    00142             if ( !stack_unwinding_in_progress )
    00143                 internal::throw_exception( internal::eid_missing_wait );
    00144         }
    00145         else {
    00146             task::destroy(*my_root);
    00147         }
    00148     }
    00149
    00150     template<typename F>
    00151     void run( task_handle<F>& h ) {
    00152         internal_run< task_handle<F>, internal::task_handle_task<F> >( h );
    00153     }
    00154
    00155     task_group_status wait() {
    00156         __TBB_TRY {
    00157             my_root->wait_for_all();
    00158         } __TBB_CATCH( ... ) {
    00159             my_context.reset();
    00160             __TBB_RETHROW();
    00161         }
    00162         if ( my_context.is_group_execution_cancelled() ) {
    00163             my_context.reset();
    00164             return canceled;
    00165         }
    00166         return complete;
    00167     }
    00168
    00169     bool is_canceling() {
    00170         return my_context.is_group_execution_cancelled();
    00171     }
    00172
    00173     void cancel() {
    00174         my_context.cancel_group_execution();
    00175     }
    00176 }; // class task_group_base
    00177
    00178 } // namespace internal
    00179
    00180 class task_group : public internal::task_group_base {
    00181 public:
    00182     task_group () : task_group_base( task_group_context::concurrent_wait ) {}
    00183
    00184 #if TBB_DEPRECATED
    00185     ~task_group() __TBB_TRY {
    00186         __TBB_ASSERT( my_root->ref_count() != 0, NULL );
    00187         if( my_root->ref_count() > 1 )
    00188             my_root->wait_for_all();
    00189     }
    00190 #if TBB_USE_EXCEPTIONS
    00191     catch (...) {
    00192         // Have to destroy my_root here as the base class destructor won't be called
    00193         task::destroy(*my_root);
    00194         throw;
    00195     }
    00196 #endif /* TBB_USE_EXCEPTIONS */
    00197 #endif /* TBB_DEPRECATED */
    00198
    00199 #if __SUNPRO_CC
    00200     template<typename F>
    00201     void run( task_handle<F>& h ) {
    00202         internal_run< task_handle<F>, internal::task_handle_task<F> >( h );
    00203     }
    00204 #else
    00205     using task_group_base::run;
    00206 #endif
    00207
    00208     template<typename F>
    00209     void run( const F& f ) {
    00210         internal_run< const F, internal::function_task<F> >( f );
    00211     }
    00212
    00213     template<typename F>
    00214     task_group_status run_and_wait( const F& f ) {
    00215         return internal_run_and_wait<const F>( f );
    00216     }
    00217
    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 }; // class task_group
    00223
    00224 class structured_task_group : public internal::task_group_base {
    00225 public:
    00226     template<typename F>
    00227     task_group_status run_and_wait ( task_handle<F>& h ) {
    00228         return internal_run_and_wait< task_handle<F> >( h );
    00229     }
    00230
    00231     task_group_status wait() {
    00232         task_group_status res = task_group_base::wait();
    00233         my_root->set_ref_count(1);
    00234         return res;
    00235     }
    00236 }; // class structured_task_group
    00237
    00238 inline
    00239 bool is_current_task_group_canceling() {
    00240     return task::self().is_cancelled();
    00241 }
    00242
    00243 template<class F>
    00244 task_handle<F> make_task( const F& f ) {
    00245     return task_handle<F>( f );
    00246 }
    00247
    00248 } // namespace tbb
    00249
    00250 #endif /* __TBB_TASK_GROUP_CONTEXT */
    00251
    00252 #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.