parallel_for.h Source File

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

- File List
- File Members

# 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 "task.h"
    00025 #include "partitioner.h"
    00026 #include "blocked_range.h"
    00027 #include <new>
    00028 #include "tbb_exception.h"
    00029
    00030 namespace tbb {
    00031
    00033 namespace internal {
    00034
    00036
    00037     template<typename Range, typename Body, typename Partitioner>
    00038     class start_for: public task {
    00039         Range my_range;
    00040         const Body my_body;
    00041         typename Partitioner::partition_type my_partition;
    00042         /*override*/ task* execute();
    00043
    00045         start_for( const Range& range, const Body& body, Partitioner& partitioner ) :
    00046             my_range(range),
    00047             my_body(body),
    00048             my_partition(partitioner)
    00049         {
    00050         }
    00052
    00053         start_for( start_for& parent_, split ) :
    00054             my_range(parent_.my_range,split()),
    00055             my_body(parent_.my_body),
    00056             my_partition(parent_.my_partition,split())
    00057         {
    00058             my_partition.set_affinity(*this);
    00059         }
    00061         /*override*/ void note_affinity( affinity_id id ) {
    00062             my_partition.note_affinity( id );
    00063         }
    00064     public:
    00065         static void run(  const Range& range, const Body& body, const Partitioner& partitioner ) {
    00066             if( !range.empty() ) {
    00067 #if !__TBB_TASK_GROUP_CONTEXT || TBB_JOIN_OUTER_TASK_GROUP
    00068                 start_for& a = *new(task::allocate_root()) start_for(range,body,const_cast<Partitioner&>(partitioner));
    00069 #else
    00070                 // Bound context prevents exceptions from body to affect nesting or sibling algorithms,
    00071                 // and allows users to handle exceptions safely by wrapping parallel_for in the try-block.
    00072                 task_group_context context;
    00073                 start_for& a = *new(task::allocate_root(context)) start_for(range,body,const_cast<Partitioner&>(partitioner));
    00074 #endif /* __TBB_TASK_GROUP_CONTEXT && !TBB_JOIN_OUTER_TASK_GROUP */
    00075                 task::spawn_root_and_wait(a);
    00076             }
    00077         }
    00078 #if __TBB_TASK_GROUP_CONTEXT
    00079         static void run(  const Range& range, const Body& body, const Partitioner& partitioner, task_group_context& context ) {
    00080             if( !range.empty() ) {
    00081                 start_for& a = *new(task::allocate_root(context)) start_for(range,body,const_cast<Partitioner&>(partitioner));
    00082                 task::spawn_root_and_wait(a);
    00083             }
    00084         }
    00085 #endif /* __TBB_TASK_GROUP_CONTEXT */
    00086     };
    00087
    00088     template<typename Range, typename Body, typename Partitioner>
    00089     task* start_for<Range,Body,Partitioner>::execute() {
    00090         if( !my_range.is_divisible() || my_partition.should_execute_range(*this) ) {
    00091             my_body( my_range );
    00092             return my_partition.continue_after_execute_range();
    00093         } else {
    00094             empty_task& c = *new( this->allocate_continuation() ) empty_task;
    00095             recycle_as_child_of(c);
    00096             c.set_ref_count(2);
    00097             bool delay = my_partition.decide_whether_to_delay();
    00098             start_for& b = *new( c.allocate_child() ) start_for(*this,split());
    00099             my_partition.spawn_or_delay(delay,b);
    00100             return this;
    00101         }
    00102     }
    00103 } // namespace internal
    00105
    00106
    00107 // Requirements on Range concept are documented in blocked_range.h
    00108
    00119
    00121
    00122 template<typename Range, typename Body>
    00123 void parallel_for( const Range& range, const Body& body ) {
    00124     internal::start_for<Range,Body,__TBB_DEFAULT_PARTITIONER>::run(range,body,__TBB_DEFAULT_PARTITIONER());
    00125 }
    00126
    00128
    00129 template<typename Range, typename Body>
    00130 void parallel_for( const Range& range, const Body& body, const simple_partitioner& partitioner ) {
    00131     internal::start_for<Range,Body,simple_partitioner>::run(range,body,partitioner);
    00132 }
    00133
    00135
    00136 template<typename Range, typename Body>
    00137 void parallel_for( const Range& range, const Body& body, const auto_partitioner& partitioner ) {
    00138     internal::start_for<Range,Body,auto_partitioner>::run(range,body,partitioner);
    00139 }
    00140
    00142
    00143 template<typename Range, typename Body>
    00144 void parallel_for( const Range& range, const Body& body, affinity_partitioner& partitioner ) {
    00145     internal::start_for<Range,Body,affinity_partitioner>::run(range,body,partitioner);
    00146 }
    00147
    00148 #if __TBB_TASK_GROUP_CONTEXT
    00150
    00151 template<typename Range, typename Body>
    00152 void parallel_for( const Range& range, const Body& body, const simple_partitioner& partitioner, task_group_context& context ) {
    00153     internal::start_for<Range,Body,simple_partitioner>::run(range, body, partitioner, context);
    00154 }
    00155
    00157
    00158 template<typename Range, typename Body>
    00159 void parallel_for( const Range& range, const Body& body, const auto_partitioner& partitioner, task_group_context& context ) {
    00160     internal::start_for<Range,Body,auto_partitioner>::run(range, body, partitioner, context);
    00161 }
    00162
    00164
    00165 template<typename Range, typename Body>
    00166 void parallel_for( const Range& range, const Body& body, affinity_partitioner& partitioner, task_group_context& context ) {
    00167     internal::start_for<Range,Body,affinity_partitioner>::run(range,body,partitioner, context);
    00168 }
    00169 #endif /* __TBB_TASK_GROUP_CONTEXT */
    00170
    00171
    00173 namespace internal {
    00175 template<typename Function, typename Index>
    00176 class parallel_for_body : internal::no_assign {
    00177     const Function &my_func;
    00178     const Index my_begin;
    00179     const Index my_step;
    00180 public:
    00181     parallel_for_body( const Function& _func, Index& _begin, Index& _step)
    00182         : my_func(_func), my_begin(_begin), my_step(_step) {}
    00183
    00184     void operator()( tbb::blocked_range<Index>& r ) const {
    00185         for( Index i = r.begin(),  k = my_begin + i * my_step; i < r.end(); i++, k = k + my_step)
    00186             my_func( k );
    00187     }
    00188 };
    00189 } // namespace internal
    00191
    00192 namespace strict_ppl {
    00193
    00195
    00196 template <typename Index, typename Function>
    00197 void parallel_for(Index first, Index last, Index step, const Function& f) {
    00198     if (step <= 0 )
    00199         internal::throw_exception(internal::eid_nonpositive_step); // throws std::invalid_argument
    00200     else if (last > first) {
    00201         // Above "else" avoids "potential divide by zero" warning on some platforms
    00202         Index end = (last - first - Index(1)) / step + Index(1);
    00203         tbb::blocked_range<Index> range(static_cast<Index>(0), end);
    00204         internal::parallel_for_body<Function, Index> body(f, first, step);
    00205         tbb::parallel_for(range, body, tbb::auto_partitioner());
    00206     }
    00207 }
    00209 template <typename Index, typename Function>
    00210 void parallel_for(Index first, Index last, const Function& f) {
    00211     parallel_for(first, last, static_cast<Index>(1), f);
    00212 }
    00213
    00214 #if __TBB_TASK_GROUP_CONTEXT
    00216 template <typename Index, typename Function>
    00217 void parallel_for(Index first, Index last, Index step, const Function& f, tbb::task_group_context &context) {
    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, tbb::auto_partitioner(), context);
    00226     }
    00227 }
    00229 template <typename Index, typename Function>
    00230 void parallel_for(Index first, Index last, const Function& f, tbb::task_group_context &context) {
    00231     parallel_for(first, last, static_cast<Index>(1), f, context);
    00232 }
    00233 #endif /* __TBB_TASK_GROUP_CONTEXT */
    00234
    00235
    00236 } // namespace strict_ppl
    00237
    00238 using strict_ppl::parallel_for;
    00239
    00240 } // namespace tbb
    00241
    00242 #endif /* __TBB_parallel_for_H */
    00243

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.