parallel_for.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_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_EXCEPTIONS || 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_EXCEPTIONS && !TBB_JOIN_OUTER_TASK_GROUP */
00075                 task::spawn_root_and_wait(a);
00076             }
00077         }
00078 #if __TBB_EXCEPTIONS
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_EXCEPTIONS */
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(*this); 
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,*this,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_EXCEPTIONS
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_EXCEPTIONS */
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     tbb::task_group_context context;
00199     parallel_for(first, last, step, f, context);
00200 }
00201 template <typename Index, typename Function>
00202 void parallel_for(Index first, Index last, Index step, const Function& f, tbb::task_group_context &context) {
00203     if (step <= 0 )
00204         internal::throw_exception(internal::eid_nonpositive_step); // throws std::invalid_argument
00205     else if (last > first) {
00206         Index end = (last - first) / step;
00207         if (first + end * step < last) end++;
00208         tbb::blocked_range<Index> range(static_cast<Index>(0), end);
00209         internal::parallel_for_body<Function, Index> body(f, first, step);
00210         tbb::parallel_for(range, body, tbb::auto_partitioner(), context);
00211     }
00212 }
00214 template <typename Index, typename Function>
00215 void parallel_for(Index first, Index last, const Function& f) {
00216     tbb::task_group_context context;
00217     parallel_for(first, last, static_cast<Index>(1), f, context);
00218 }
00219 template <typename Index, typename Function>
00220 void parallel_for(Index first, Index last, const Function& f, tbb::task_group_context &context) {
00221     parallel_for(first, last, static_cast<Index>(1), f, context);
00222 }
00223 
00225 
00226 } // namespace strict_ppl
00227 
00228 using strict_ppl::parallel_for;
00229 
00230 } // namespace tbb
00231 
00232 #endif /* __TBB_parallel_for_H */
00233 

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