00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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 <stdexcept>
00029 #include <string>
00030
00031 namespace tbb {
00032
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::partition_type my_partition;
00043 task* execute();
00044
00046 start_for( const Range& range, const Body& body, Partitioner& partitioner ) :
00047 my_range(range),
00048 my_body(body),
00049 my_partition(partitioner)
00050 {
00051 }
00053
00054 start_for( start_for& parent, split ) :
00055 my_range(parent.my_range,split()),
00056 my_body(parent.my_body),
00057 my_partition(parent.my_partition,split())
00058 {
00059 my_partition.set_affinity(*this);
00060 }
00062 void note_affinity( affinity_id id ) {
00063 my_partition.note_affinity( id );
00064 }
00065 public:
00066 static void run( const Range& range, const Body& body, const Partitioner& partitioner ) {
00067 if( !range.empty() ) {
00068 #if !__TBB_EXCEPTIONS || TBB_JOIN_OUTER_TASK_GROUP
00069 start_for& a = *new(task::allocate_root()) start_for(range,body,const_cast<Partitioner&>(partitioner));
00070 #else
00071
00072
00073 task_group_context context;
00074 start_for& a = *new(task::allocate_root(context)) start_for(range,body,const_cast<Partitioner&>(partitioner));
00075 #endif
00076 task::spawn_root_and_wait(a);
00077 }
00078 }
00079 #if __TBB_EXCEPTIONS
00080 static void run( const Range& range, const Body& body, const Partitioner& partitioner, task_group_context& context ) {
00081 if( !range.empty() ) {
00082 start_for& a = *new(task::allocate_root(context)) start_for(range,body,const_cast<Partitioner&>(partitioner));
00083 task::spawn_root_and_wait(a);
00084 }
00085 }
00086 #endif
00087 };
00088
00089 template<typename Range, typename Body, typename Partitioner>
00090 task* start_for<Range,Body,Partitioner>::execute() {
00091 if( !my_range.is_divisible() || my_partition.should_execute_range(*this) ) {
00092 my_body( my_range );
00093 return my_partition.continue_after_execute_range(*this);
00094 } else {
00095 empty_task& c = *new( this->allocate_continuation() ) empty_task;
00096 recycle_as_child_of(c);
00097 c.set_ref_count(2);
00098 bool delay = my_partition.decide_whether_to_delay();
00099 start_for& b = *new( c.allocate_child() ) start_for(*this,split());
00100 my_partition.spawn_or_delay(delay,*this,b);
00101 return this;
00102 }
00103 }
00104 }
00106
00107
00108
00109
00120
00122
00123 template<typename Range, typename Body>
00124 void parallel_for( const Range& range, const Body& body ) {
00125 internal::start_for<Range,Body,__TBB_DEFAULT_PARTITIONER>::run(range,body,__TBB_DEFAULT_PARTITIONER());
00126 }
00127
00129
00130 template<typename Range, typename Body>
00131 void parallel_for( const Range& range, const Body& body, const simple_partitioner& partitioner ) {
00132 internal::start_for<Range,Body,simple_partitioner>::run(range,body,partitioner);
00133 }
00134
00136
00137 template<typename Range, typename Body>
00138 void parallel_for( const Range& range, const Body& body, const auto_partitioner& partitioner ) {
00139 internal::start_for<Range,Body,auto_partitioner>::run(range,body,partitioner);
00140 }
00141
00143
00144 template<typename Range, typename Body>
00145 void parallel_for( const Range& range, const Body& body, affinity_partitioner& partitioner ) {
00146 internal::start_for<Range,Body,affinity_partitioner>::run(range,body,partitioner);
00147 }
00148
00149 #if __TBB_EXCEPTIONS
00151
00152 template<typename Range, typename Body>
00153 void parallel_for( const Range& range, const Body& body, const simple_partitioner& partitioner, task_group_context& context ) {
00154 internal::start_for<Range,Body,simple_partitioner>::run(range, body, partitioner, context);
00155 }
00156
00158
00159 template<typename Range, typename Body>
00160 void parallel_for( const Range& range, const Body& body, const auto_partitioner& partitioner, task_group_context& context ) {
00161 internal::start_for<Range,Body,auto_partitioner>::run(range, body, partitioner, context);
00162 }
00163
00165
00166 template<typename Range, typename Body>
00167 void parallel_for( const Range& range, const Body& body, affinity_partitioner& partitioner, task_group_context& context ) {
00168 internal::start_for<Range,Body,affinity_partitioner>::run(range,body,partitioner, context);
00169 }
00170 #endif
00171
00172
00174 namespace internal {
00176 template<typename Function, typename Index>
00177 class parallel_for_body : internal::no_assign {
00178 const Function &my_func;
00179 const Index my_begin;
00180 const Index my_step;
00181 public:
00182 parallel_for_body( const Function& _func, Index& _begin, Index& _step)
00183 : my_func(_func), my_begin(_begin), my_step(_step) {}
00184
00185 void operator()( tbb::blocked_range<Index>& r ) const {
00186 for( Index i = r.begin(), k = my_begin + i * my_step; i < r.end(); i++, k = k + my_step)
00187 my_func( k );
00188 }
00189 };
00190 }
00192
00193 namespace strict_ppl {
00194
00196
00197 template <typename Index, typename Function>
00198 void parallel_for(Index first, Index last, Index step, const Function& f) {
00199 tbb::task_group_context context;
00200 parallel_for(first, last, step, f, context);
00201 }
00202 template <typename Index, typename Function>
00203 void parallel_for(Index first, Index last, Index step, const Function& f, tbb::task_group_context &context) {
00204 if (step <= 0 ) throw std::invalid_argument("step should be positive");
00205
00206 if (last > first) {
00207 Index end = (last - first) / step;
00208 if (first + end * step < last) end++;
00209 tbb::blocked_range<Index> range(static_cast<Index>(0), end);
00210 internal::parallel_for_body<Function, Index> body(f, first, step);
00211 tbb::parallel_for(range, body, tbb::auto_partitioner(), context);
00212 }
00213 }
00215 template <typename Index, typename Function>
00216 void parallel_for(Index first, Index last, const Function& f) {
00217 tbb::task_group_context context;
00218 parallel_for(first, last, static_cast<Index>(1), f, context);
00219 }
00220 template <typename Index, typename Function>
00221 void parallel_for(Index first, Index last, const Function& f, tbb::task_group_context &context) {
00222 parallel_for(first, last, static_cast<Index>(1), f, context);
00223 }
00224
00226
00227 }
00228
00229 using strict_ppl::parallel_for;
00230
00231 }
00232
00233 #endif
00234