parallel_for.h

00001 /*
00002     Copyright 2005-2011 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_parallel_for_H
00022 #define __TBB_parallel_for_H
00023 
00024 #include <new>
00025 #include "task.h"
00026 #include "partitioner.h"
00027 #include "blocked_range.h"
00028 #include "tbb_exception.h"
00029 
00030 namespace tbb {
00031 
00032 namespace interface6 {
00034 namespace internal {
00035 
00037 
00038     template<typename Range, typename Body, typename Partitioner>
00039     class start_for: public task {
00040         Range my_range;
00041         const Body my_body;
00042         typename Partitioner::task_partition_type my_partition;
00043         /*override*/ task* execute();
00044 
00045     public:
00047         start_for( const Range& range, const Body& body, Partitioner& partitioner ) :
00048             my_range(range),    
00049             my_body(body),
00050             my_partition(partitioner)
00051         {
00052         }
00054 
00055         start_for( start_for& parent_, split ) :
00056             my_range(parent_.my_range,split()),
00057             my_body(parent_.my_body),
00058             my_partition(parent_.my_partition, split())
00059         {
00060             my_partition.set_affinity(*this);
00061         }
00063 
00064         start_for( start_for& parent_, const Range& r, depth_t d ) :
00065             my_range(r),
00066             my_body(parent_.my_body),
00067             my_partition(parent_.my_partition,split())
00068         {
00069             my_partition.set_affinity(*this);
00070             my_partition.align_depth( d );
00071         }
00073         /*override*/ void note_affinity( affinity_id id ) {
00074             my_partition.note_affinity( id );
00075         }
00076         static void run(  const Range& range, const Body& body, const Partitioner& partitioner ) {
00077             if( !range.empty() ) {
00078 #if !__TBB_TASK_GROUP_CONTEXT || TBB_JOIN_OUTER_TASK_GROUP
00079                 start_for& a = *new(task::allocate_root()) start_for(range,body,const_cast<Partitioner&>(partitioner));
00080 #else
00081                 // Bound context prevents exceptions from body to affect nesting or sibling algorithms,
00082                 // and allows users to handle exceptions safely by wrapping parallel_for in the try-block.
00083                 task_group_context context;
00084                 start_for& a = *new(task::allocate_root(context)) start_for(range,body,const_cast<Partitioner&>(partitioner));
00085 #endif /* __TBB_TASK_GROUP_CONTEXT && !TBB_JOIN_OUTER_TASK_GROUP */
00086                 task::spawn_root_and_wait(a);
00087             }
00088         }
00089 #if __TBB_TASK_GROUP_CONTEXT
00090         static void run(  const Range& range, const Body& body, const Partitioner& partitioner, task_group_context& context ) {
00091             if( !range.empty() ) {
00092                 start_for& a = *new(task::allocate_root(context)) start_for(range,body,const_cast<Partitioner&>(partitioner));
00093                 task::spawn_root_and_wait(a);
00094             }
00095         }
00096 #endif /* __TBB_TASK_GROUP_CONTEXT */
00098         flag_task *create_continuation() {
00099             return new( allocate_continuation() ) flag_task();
00100         }
00102         void run_body( Range &r ) { my_body( r ); }
00103     };
00104 
00105     template<typename Range, typename Body, typename Partitioner>
00106     task* start_for<Range,Body,Partitioner>::execute() {
00107         my_partition.check_being_stolen( *this );
00108         my_partition.execute(*this, my_range);
00109         return NULL;
00110     } 
00111 } // namespace internal
00113 } // namespace interfaceX
00114 
00116 namespace internal {
00117     using interface6::internal::start_for;
00118     
00120     template<typename Function, typename Index>
00121     class parallel_for_body : internal::no_assign {
00122         const Function &my_func;
00123         const Index my_begin;
00124         const Index my_step; 
00125     public:
00126         parallel_for_body( const Function& _func, Index& _begin, Index& _step) 
00127             : my_func(_func), my_begin(_begin), my_step(_step) {}
00128         
00129         void operator()( tbb::blocked_range<Index>& r ) const {
00130             for( Index i = r.begin(),  k = my_begin + i * my_step; i < r.end(); i++, k = k + my_step)
00131                 my_func( k );
00132         }
00133     };
00134 } // namespace internal
00136 
00137 // Requirements on Range concept are documented in blocked_range.h
00138 
00149 
00151 
00152 template<typename Range, typename Body>
00153 void parallel_for( const Range& range, const Body& body ) {
00154     internal::start_for<Range,Body,__TBB_DEFAULT_PARTITIONER>::run(range,body,__TBB_DEFAULT_PARTITIONER());
00155 }
00156 
00158 
00159 template<typename Range, typename Body>
00160 void parallel_for( const Range& range, const Body& body, const simple_partitioner& partitioner ) {
00161     internal::start_for<Range,Body,simple_partitioner>::run(range,body,partitioner);
00162 }
00163 
00165 
00166 template<typename Range, typename Body>
00167 void parallel_for( const Range& range, const Body& body, const auto_partitioner& partitioner ) {
00168     internal::start_for<Range,Body,auto_partitioner>::run(range,body,partitioner);
00169 }
00170 
00172 
00173 template<typename Range, typename Body>
00174 void parallel_for( const Range& range, const Body& body, affinity_partitioner& partitioner ) {
00175     internal::start_for<Range,Body,affinity_partitioner>::run(range,body,partitioner);
00176 }
00177 
00178 #if __TBB_TASK_GROUP_CONTEXT
00180 
00181 template<typename Range, typename Body>
00182 void parallel_for( const Range& range, const Body& body, const simple_partitioner& partitioner, task_group_context& context ) {
00183     internal::start_for<Range,Body,simple_partitioner>::run(range, body, partitioner, context);
00184 }
00185 
00187 
00188 template<typename Range, typename Body>
00189 void parallel_for( const Range& range, const Body& body, const auto_partitioner& partitioner, task_group_context& context ) {
00190     internal::start_for<Range,Body,auto_partitioner>::run(range, body, partitioner, context);
00191 }
00192 
00194 
00195 template<typename Range, typename Body>
00196 void parallel_for( const Range& range, const Body& body, affinity_partitioner& partitioner, task_group_context& context ) {
00197     internal::start_for<Range,Body,affinity_partitioner>::run(range,body,partitioner, context);
00198 }
00199 #endif /* __TBB_TASK_GROUP_CONTEXT */
00200 
00201 
00202 namespace strict_ppl {
00203 
00205 
00206 template <typename Index, typename Function>
00207 void parallel_for(Index first, Index last, Index step, const Function& f) {
00208     if (step <= 0 )
00209         internal::throw_exception(internal::eid_nonpositive_step); // throws std::invalid_argument
00210     else if (last > first) {
00211         // Above "else" avoids "potential divide by zero" warning on some platforms
00212         Index end = (last - first - Index(1)) / step + Index(1);
00213         tbb::blocked_range<Index> range(static_cast<Index>(0), end);
00214         internal::parallel_for_body<Function, Index> body(f, first, step);
00215         tbb::parallel_for(range, body, tbb::auto_partitioner());
00216     }
00217 }
00219 template <typename Index, typename Function>
00220 void parallel_for(Index first, Index last, const Function& f) {
00221     parallel_for(first, last, static_cast<Index>(1), f);
00222 }
00223 
00224 #if __TBB_TASK_GROUP_CONTEXT
00226 template <typename Index, typename Function>
00227 void parallel_for(Index first, Index last, Index step, const Function& f, tbb::task_group_context &context) {
00228     if (step <= 0 )
00229         internal::throw_exception(internal::eid_nonpositive_step); // throws std::invalid_argument
00230     else if (last > first) {
00231         // Above "else" avoids "potential divide by zero" warning on some platforms
00232         Index end = (last - first - Index(1)) / step + Index(1);
00233         tbb::blocked_range<Index> range(static_cast<Index>(0), end);
00234         internal::parallel_for_body<Function, Index> body(f, first, step);
00235         tbb::parallel_for(range, body, tbb::auto_partitioner(), context);
00236     }
00237 }
00239 template <typename Index, typename Function>
00240 void parallel_for(Index first, Index last, const Function& f, tbb::task_group_context &context) {
00241     parallel_for(first, last, static_cast<Index>(1), f, context);
00242 }
00243 #endif /* __TBB_TASK_GROUP_CONTEXT */
00244 
00245 
00246 } // namespace strict_ppl
00247 
00248 using strict_ppl::parallel_for;
00249 
00250 } // namespace tbb
00251 
00252 #if TBB_PREVIEW_SERIAL_SUBSET
00253 #define __TBB_NORMAL_EXECUTION
00254 #include "../serial/tbb/parallel_for.h"
00255 #undef __TBB_NORMAL_EXECUTION
00256 #endif
00257 
00258 #endif /* __TBB_parallel_for_H */
00259 

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