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 "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 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 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
00071
00072 task_group_context context;
00073 start_for& a = *new(task::allocate_root(context)) start_for(range,body,const_cast<Partitioner&>(partitioner));
00074 #endif
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
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 }
00105
00106
00107
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
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 }
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);
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 }
00227
00228 using strict_ppl::parallel_for;
00229
00230 }
00231
00232 #endif
00233