2 Copyright 2005-2011 Intel Corporation. All Rights Reserved.
4 This file is part of Threading Building Blocks.
6 Threading Building Blocks is free software; you can redistribute it
7 and/or modify it under the terms of the GNU General Public License
8 version 2 as published by the Free Software Foundation.
10 Threading Building Blocks is distributed in the hope that it will be
11 useful, but WITHOUT ANY WARRANTY; without even the implied warranty
12 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with Threading Building Blocks; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 As a special exception, you may use this file as part of a free software
20 library without restriction. Specifically, if other files instantiate
21 templates or use macros or inline functions from this file, or you compile
22 this file and link it with other files to produce an executable, this
23 file does not by itself cause the resulting executable to be covered by
24 the GNU General Public License. This exception does not however
25 invalidate any other reasons why the executable file might be covered by
26 the GNU General Public License.
29 #ifndef __TBB_parallel_for_H
30 #define __TBB_parallel_for_H
33 #include "partitioner.h"
34 #include "blocked_range.h"
36 #include "tbb_exception.h"
43 //! Task type used in parallel_for
44 /** @ingroup algorithms */
45 template<typename Range, typename Body, typename Partitioner>
46 class start_for: public task {
49 typename Partitioner::partition_type my_partition;
50 /*override*/ task* execute();
52 //! Constructor for root task.
53 start_for( const Range& range, const Body& body, Partitioner& partitioner ) :
56 my_partition(partitioner)
59 //! Splitting constructor used to generate children.
60 /** this becomes left child. Newly constructed object is right child. */
61 start_for( start_for& parent_, split ) :
62 my_range(parent_.my_range,split()),
63 my_body(parent_.my_body),
64 my_partition(parent_.my_partition,split())
66 my_partition.set_affinity(*this);
68 //! Update affinity info, if any.
69 /*override*/ void note_affinity( affinity_id id ) {
70 my_partition.note_affinity( id );
73 static void run( const Range& range, const Body& body, const Partitioner& partitioner ) {
74 if( !range.empty() ) {
75 #if !__TBB_TASK_GROUP_CONTEXT || TBB_JOIN_OUTER_TASK_GROUP
76 start_for& a = *new(task::allocate_root()) start_for(range,body,const_cast<Partitioner&>(partitioner));
78 // Bound context prevents exceptions from body to affect nesting or sibling algorithms,
79 // and allows users to handle exceptions safely by wrapping parallel_for in the try-block.
80 task_group_context context;
81 start_for& a = *new(task::allocate_root(context)) start_for(range,body,const_cast<Partitioner&>(partitioner));
82 #endif /* __TBB_TASK_GROUP_CONTEXT && !TBB_JOIN_OUTER_TASK_GROUP */
83 task::spawn_root_and_wait(a);
86 #if __TBB_TASK_GROUP_CONTEXT
87 static void run( const Range& range, const Body& body, const Partitioner& partitioner, task_group_context& context ) {
88 if( !range.empty() ) {
89 start_for& a = *new(task::allocate_root(context)) start_for(range,body,const_cast<Partitioner&>(partitioner));
90 task::spawn_root_and_wait(a);
93 #endif /* __TBB_TASK_GROUP_CONTEXT */
96 template<typename Range, typename Body, typename Partitioner>
97 task* start_for<Range,Body,Partitioner>::execute() {
98 if( !my_range.is_divisible() || my_partition.should_execute_range(*this) ) {
100 return my_partition.continue_after_execute_range();
102 empty_task& c = *new( this->allocate_continuation() ) empty_task;
103 recycle_as_child_of(c);
105 bool delay = my_partition.decide_whether_to_delay();
106 start_for& b = *new( c.allocate_child() ) start_for(*this,split());
107 my_partition.spawn_or_delay(delay,b);
111 } // namespace internal
115 // Requirements on Range concept are documented in blocked_range.h
117 /** \page parallel_for_body_req Requirements on parallel_for body
118 Class \c Body implementing the concept of parallel_for body must define:
119 - \code Body::Body( const Body& ); \endcode Copy constructor
120 - \code Body::~Body(); \endcode Destructor
121 - \code void Body::operator()( Range& r ) const; \endcode Function call operator applying the body to range \c r.
124 /** \name parallel_for
125 See also requirements on \ref range_req "Range" and \ref parallel_for_body_req "parallel_for Body". **/
128 //! Parallel iteration over range with default partitioner.
129 /** @ingroup algorithms **/
130 template<typename Range, typename Body>
131 void parallel_for( const Range& range, const Body& body ) {
132 internal::start_for<Range,Body,__TBB_DEFAULT_PARTITIONER>::run(range,body,__TBB_DEFAULT_PARTITIONER());
135 //! Parallel iteration over range with simple partitioner.
136 /** @ingroup algorithms **/
137 template<typename Range, typename Body>
138 void parallel_for( const Range& range, const Body& body, const simple_partitioner& partitioner ) {
139 internal::start_for<Range,Body,simple_partitioner>::run(range,body,partitioner);
142 //! Parallel iteration over range with auto_partitioner.
143 /** @ingroup algorithms **/
144 template<typename Range, typename Body>
145 void parallel_for( const Range& range, const Body& body, const auto_partitioner& partitioner ) {
146 internal::start_for<Range,Body,auto_partitioner>::run(range,body,partitioner);
149 //! Parallel iteration over range with affinity_partitioner.
150 /** @ingroup algorithms **/
151 template<typename Range, typename Body>
152 void parallel_for( const Range& range, const Body& body, affinity_partitioner& partitioner ) {
153 internal::start_for<Range,Body,affinity_partitioner>::run(range,body,partitioner);
156 #if __TBB_TASK_GROUP_CONTEXT
157 //! Parallel iteration over range with simple partitioner and user-supplied context.
158 /** @ingroup algorithms **/
159 template<typename Range, typename Body>
160 void parallel_for( const Range& range, const Body& body, const simple_partitioner& partitioner, task_group_context& context ) {
161 internal::start_for<Range,Body,simple_partitioner>::run(range, body, partitioner, context);
164 //! Parallel iteration over range with auto_partitioner and user-supplied context.
165 /** @ingroup algorithms **/
166 template<typename Range, typename Body>
167 void parallel_for( const Range& range, const Body& body, const auto_partitioner& partitioner, task_group_context& context ) {
168 internal::start_for<Range,Body,auto_partitioner>::run(range, body, partitioner, context);
171 //! Parallel iteration over range with affinity_partitioner and user-supplied context.
172 /** @ingroup algorithms **/
173 template<typename Range, typename Body>
174 void parallel_for( const Range& range, const Body& body, affinity_partitioner& partitioner, task_group_context& context ) {
175 internal::start_for<Range,Body,affinity_partitioner>::run(range,body,partitioner, context);
177 #endif /* __TBB_TASK_GROUP_CONTEXT */
182 //! Calls the function with values from range [begin, end) with a step provided
183 template<typename Function, typename Index>
184 class parallel_for_body : internal::no_assign {
185 const Function &my_func;
186 const Index my_begin;
189 parallel_for_body( const Function& _func, Index& _begin, Index& _step)
190 : my_func(_func), my_begin(_begin), my_step(_step) {}
192 void operator()( tbb::blocked_range<Index>& r ) const {
193 for( Index i = r.begin(), k = my_begin + i * my_step; i < r.end(); i++, k = k + my_step)
197 } // namespace internal
200 namespace strict_ppl {
203 //! Parallel iteration over a range of integers with a step provided
204 template <typename Index, typename Function>
205 void parallel_for(Index first, Index last, Index step, const Function& f) {
207 internal::throw_exception(internal::eid_nonpositive_step); // throws std::invalid_argument
208 else if (last > first) {
209 // Above "else" avoids "potential divide by zero" warning on some platforms
210 Index end = (last - first - Index(1)) / step + Index(1);
211 tbb::blocked_range<Index> range(static_cast<Index>(0), end);
212 internal::parallel_for_body<Function, Index> body(f, first, step);
213 tbb::parallel_for(range, body, tbb::auto_partitioner());
216 //! Parallel iteration over a range of integers with a default step value
217 template <typename Index, typename Function>
218 void parallel_for(Index first, Index last, const Function& f) {
219 parallel_for(first, last, static_cast<Index>(1), f);
222 #if __TBB_TASK_GROUP_CONTEXT
223 //! Parallel iteration over a range of integers with explicit step and task group context
224 template <typename Index, typename Function>
225 void parallel_for(Index first, Index last, Index step, const Function& f, tbb::task_group_context &context) {
227 internal::throw_exception(internal::eid_nonpositive_step); // throws std::invalid_argument
228 else if (last > first) {
229 // Above "else" avoids "potential divide by zero" warning on some platforms
230 Index end = (last - first - Index(1)) / step + Index(1);
231 tbb::blocked_range<Index> range(static_cast<Index>(0), end);
232 internal::parallel_for_body<Function, Index> body(f, first, step);
233 tbb::parallel_for(range, body, tbb::auto_partitioner(), context);
236 //! Parallel iteration over a range of integers with a default step value and explicit task group context
237 template <typename Index, typename Function>
238 void parallel_for(Index first, Index last, const Function& f, tbb::task_group_context &context) {
239 parallel_for(first, last, static_cast<Index>(1), f, context);
241 #endif /* __TBB_TASK_GROUP_CONTEXT */
244 } // namespace strict_ppl
246 using strict_ppl::parallel_for;
250 #endif /* __TBB_parallel_for_H */