parallel_for.h Source File

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

- File List
- File Members

# parallel_for.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_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, 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,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,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, Partitioner& partitioner, task_group_context& context ) {
    00091             if( !range.empty() ) {
    00092                 start_for& a = *new(task::allocate_root(context)) start_for(range,body,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 #if __INTEL_COMPILER
    00131 #pragma ivdep
    00132 #endif
    00133             for( Index i = r.begin(),  k = my_begin + i * my_step; i < r.end(); i++, k = k + my_step)
    00134                 my_func( k );
    00135         }
    00136     };
    00137 } // namespace internal
    00139
    00140 // Requirements on Range concept are documented in blocked_range.h
    00141
    00152
    00154
    00155 template<typename Range, typename Body>
    00156 void parallel_for( const Range& range, const Body& body ) {
    00157     internal::start_for<Range,Body,const __TBB_DEFAULT_PARTITIONER>::run(range,body,__TBB_DEFAULT_PARTITIONER());
    00158 }
    00159
    00161
    00162 template<typename Range, typename Body>
    00163 void parallel_for( const Range& range, const Body& body, const simple_partitioner& partitioner ) {
    00164     internal::start_for<Range,Body,const simple_partitioner>::run(range,body,partitioner);
    00165 }
    00166
    00168
    00169 template<typename Range, typename Body>
    00170 void parallel_for( const Range& range, const Body& body, const auto_partitioner& partitioner ) {
    00171     internal::start_for<Range,Body,const auto_partitioner>::run(range,body,partitioner);
    00172 }
    00173
    00175
    00176 template<typename Range, typename Body>
    00177 void parallel_for( const Range& range, const Body& body, affinity_partitioner& partitioner ) {
    00178     internal::start_for<Range,Body,affinity_partitioner>::run(range,body,partitioner);
    00179 }
    00180
    00181 #if __TBB_TASK_GROUP_CONTEXT
    00183
    00184 template<typename Range, typename Body>
    00185 void parallel_for( const Range& range, const Body& body, task_group_context& context ) {
    00186     internal::start_for<Range,Body,const __TBB_DEFAULT_PARTITIONER>::run(range, body, __TBB_DEFAULT_PARTITIONER(), context);
    00187 }
    00188
    00190
    00191 template<typename Range, typename Body>
    00192 void parallel_for( const Range& range, const Body& body, const simple_partitioner& partitioner, task_group_context& context ) {
    00193     internal::start_for<Range,Body,const simple_partitioner>::run(range, body, partitioner, context);
    00194 }
    00195
    00197
    00198 template<typename Range, typename Body>
    00199 void parallel_for( const Range& range, const Body& body, const auto_partitioner& partitioner, task_group_context& context ) {
    00200     internal::start_for<Range,Body,const auto_partitioner>::run(range, body, partitioner, context);
    00201 }
    00202
    00204
    00205 template<typename Range, typename Body>
    00206 void parallel_for( const Range& range, const Body& body, affinity_partitioner& partitioner, task_group_context& context ) {
    00207     internal::start_for<Range,Body,affinity_partitioner>::run(range,body,partitioner, context);
    00208 }
    00209 #endif /* __TBB_TASK_GROUP_CONTEXT */
    00210
    00211
    00212 namespace strict_ppl {
    00213
    00215
    00216 template <typename Index, typename Function, typename Partitioner>
    00217 void parallel_for_impl(Index first, Index last, Index step, const Function& f, Partitioner& partitioner) {
    00218     if (step <= 0 )
    00219         internal::throw_exception(internal::eid_nonpositive_step); // throws std::invalid_argument
    00220     else if (last > first) {
    00221         // Above "else" avoids "potential divide by zero" warning on some platforms
    00222         Index end = (last - first - Index(1)) / step + Index(1);
    00223         tbb::blocked_range<Index> range(static_cast<Index>(0), end);
    00224         internal::parallel_for_body<Function, Index> body(f, first, step);
    00225         tbb::parallel_for(range, body, partitioner);
    00226     }
    00227 }
    00228
    00230 template <typename Index, typename Function>
    00231 void parallel_for(Index first, Index last, Index step, const Function& f) {
    00232     parallel_for_impl<Index,Function,const auto_partitioner>(first, last, step, f, auto_partitioner());
    00233 }
    00235 template <typename Index, typename Function>
    00236 void parallel_for(Index first, Index last, Index step, const Function& f, const simple_partitioner& partitioner) {
    00237     parallel_for_impl<Index,Function,const simple_partitioner>(first, last, step, f, partitioner);
    00238 }
    00240 template <typename Index, typename Function>
    00241 void parallel_for(Index first, Index last, Index step, const Function& f, const auto_partitioner& partitioner) {
    00242     parallel_for_impl<Index,Function,const auto_partitioner>(first, last, step, f, partitioner);
    00243 }
    00245 template <typename Index, typename Function>
    00246 void parallel_for(Index first, Index last, Index step, const Function& f, affinity_partitioner& partitioner) {
    00247     parallel_for_impl(first, last, step, f, partitioner);
    00248 }
    00249
    00251 template <typename Index, typename Function>
    00252 void parallel_for(Index first, Index last, const Function& f) {
    00253     parallel_for_impl<Index,Function,const auto_partitioner>(first, last, static_cast<Index>(1), f, auto_partitioner());
    00254 }
    00256 template <typename Index, typename Function>
    00257 void parallel_for(Index first, Index last, const Function& f, const simple_partitioner& partitioner) {
    00258     parallel_for_impl<Index,Function,const simple_partitioner>(first, last, static_cast<Index>(1), f, partitioner);
    00259 }
    00261 template <typename Index, typename Function>
    00262 void parallel_for(Index first, Index last, const Function& f, const auto_partitioner& partitioner) {
    00263     parallel_for_impl<Index,Function,const auto_partitioner>(first, last, static_cast<Index>(1), f, partitioner);
    00264 }
    00266 template <typename Index, typename Function>
    00267 void parallel_for(Index first, Index last, const Function& f, affinity_partitioner& partitioner) {
    00268     parallel_for_impl(first, last, static_cast<Index>(1), f, partitioner);
    00269 }
    00270
    00271 #if __TBB_TASK_GROUP_CONTEXT
    00273 template <typename Index, typename Function, typename Partitioner>
    00274 void parallel_for_impl(Index first, Index last, Index step, const Function& f, Partitioner& partitioner, tbb::task_group_context &context) {
    00275     if (step <= 0 )
    00276         internal::throw_exception(internal::eid_nonpositive_step); // throws std::invalid_argument
    00277     else if (last > first) {
    00278         // Above "else" avoids "potential divide by zero" warning on some platforms
    00279         Index end = (last - first - Index(1)) / step + Index(1);
    00280         tbb::blocked_range<Index> range(static_cast<Index>(0), end);
    00281         internal::parallel_for_body<Function, Index> body(f, first, step);
    00282         tbb::parallel_for(range, body, partitioner, context);
    00283     }
    00284 }
    00285
    00287 template <typename Index, typename Function>
    00288 void parallel_for(Index first, Index last, Index step, const Function& f, tbb::task_group_context &context) {
    00289     parallel_for_impl<Index,Function,const auto_partitioner>(first, last, step, f, auto_partitioner(), context);
    00290 }
    00292  template <typename Index, typename Function>
    00293 void parallel_for(Index first, Index last, Index step, const Function& f, const simple_partitioner& partitioner, tbb::task_group_context &context) {
    00294     parallel_for_impl<Index,Function,const simple_partitioner>(first, last, step, f, partitioner, context);
    00295 }
    00297  template <typename Index, typename Function>
    00298 void parallel_for(Index first, Index last, Index step, const Function& f, const auto_partitioner& partitioner, tbb::task_group_context &context) {
    00299     parallel_for_impl<Index,Function,const auto_partitioner>(first, last, step, f, partitioner, context);
    00300 }
    00302  template <typename Index, typename Function>
    00303 void parallel_for(Index first, Index last, Index step, const Function& f, affinity_partitioner& partitioner, tbb::task_group_context &context) {
    00304     parallel_for_impl(first, last, step, f, partitioner, context);
    00305 }
    00306
    00307
    00309 template <typename Index, typename Function>
    00310 void parallel_for(Index first, Index last, const Function& f, tbb::task_group_context &context) {
    00311     parallel_for_impl<Index,Function,const auto_partitioner>(first, last, static_cast<Index>(1), f, auto_partitioner(), context);
    00312 }
    00314  template <typename Index, typename Function, typename Partitioner>
    00315 void parallel_for(Index first, Index last, const Function& f, const simple_partitioner& partitioner, tbb::task_group_context &context) {
    00316     parallel_for_impl<Index,Function,const simple_partitioner>(first, last, static_cast<Index>(1), f, partitioner, context);
    00317 }
    00319  template <typename Index, typename Function, typename Partitioner>
    00320 void parallel_for(Index first, Index last, const Function& f, const auto_partitioner& partitioner, tbb::task_group_context &context) {
    00321     parallel_for_impl<Index,Function,const auto_partitioner>(first, last, static_cast<Index>(1), f, partitioner, context);
    00322 }
    00324  template <typename Index, typename Function, typename Partitioner>
    00325 void parallel_for(Index first, Index last, const Function& f, affinity_partitioner& partitioner, tbb::task_group_context &context) {
    00326     parallel_for_impl(first, last, static_cast<Index>(1), f, partitioner, context);
    00327 }
    00328
    00329 #endif /* __TBB_TASK_GROUP_CONTEXT */
    00330
    00331
    00332 } // namespace strict_ppl
    00333
    00334 using strict_ppl::parallel_for;
    00335
    00336 } // namespace tbb
    00337
    00338 #if TBB_PREVIEW_SERIAL_SUBSET
    00339 #define __TBB_NORMAL_EXECUTION
    00340 #include "../serial/tbb/parallel_for.h"
    00341 #undef __TBB_NORMAL_EXECUTION
    00342 #endif
    00343
    00344 #endif /* __TBB_parallel_for_H */
    00345

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.