21 #ifndef __TBB_parallel_do_H 22 #define __TBB_parallel_do_H 24 #include "internal/_range_iterator.h" 25 #include "internal/_template_helpers.h" 27 #include "aligned_space.h" 34 template<
typename Body,
typename Item>
class parallel_do_feeder_impl;
35 template<
typename Body>
class do_group_task;
41 template<
typename Item>
46 virtual void internal_add(
const Item& item ) = 0;
47 template<
typename Body_,
typename Item_>
friend class internal::parallel_do_feeder_impl;
51 void add(
const Item& item ) {internal_add(item);}
59 template<
class Body,
typename Item>
60 class parallel_do_operator_selector
63 template<
typename A1,
typename A2,
typename CvItem >
64 static void internal_call(
const Body& obj, A1& arg1, A2&,
void (Body::*)(CvItem)
const ) {
67 template<
typename A1,
typename A2,
typename CvItem >
68 static void internal_call(
const Body& obj, A1& arg1, A2& arg2,
void (Body::*)(CvItem,
parallel_do_feeder<Item>&)
const ) {
73 template<
typename A1,
typename A2 >
74 static void call(
const Body& obj, A1& arg1, A2& arg2 )
76 internal_call( obj, arg1, arg2, &Body::operator() );
83 template<
typename Body,
typename Item>
84 class do_iteration_task:
public task
86 typedef parallel_do_feeder_impl<Body, Item> feeder_type;
89 feeder_type& my_feeder;
91 do_iteration_task(
const Item& value, feeder_type& feeder ) :
92 my_value(value), my_feeder(feeder)
99 parallel_do_operator_selector<Body, Item>::call(*my_feeder.my_body, my_value, my_feeder);
103 template<
typename Body_,
typename Item_>
friend class parallel_do_feeder_impl;
106 template<
typename Iterator,
typename Body,
typename Item>
107 class do_iteration_task_iter:
public task
109 typedef parallel_do_feeder_impl<Body, Item> feeder_type;
112 feeder_type& my_feeder;
114 do_iteration_task_iter(
const Iterator& iter, feeder_type& feeder ) :
115 my_iter(iter), my_feeder(feeder)
121 parallel_do_operator_selector<Body, Item>::call(*my_feeder.my_body, *my_iter, my_feeder);
125 template<
typename Iterator_,
typename Body_,
typename Item_>
friend class do_group_task_forward;
126 template<
typename Body_,
typename Item_>
friend class do_group_task_input;
127 template<
typename Iterator_,
typename Body_,
typename Item_>
friend class do_task_iter;
133 template<
class Body,
typename Item>
137 void internal_add(
const Item& item )
139 typedef do_iteration_task<Body, Item> iteration_type;
141 iteration_type& t = *
new (task::allocate_additional_child_of(*my_barrier)) iteration_type(item, *
this);
147 empty_task* my_barrier;
149 parallel_do_feeder_impl()
151 my_barrier =
new( task::allocate_root() ) empty_task();
152 __TBB_ASSERT(my_barrier,
"root task allocation failed");
155 #if __TBB_TASK_GROUP_CONTEXT 156 parallel_do_feeder_impl(tbb::task_group_context &context)
158 my_barrier =
new( task::allocate_root(context) ) empty_task();
159 __TBB_ASSERT(my_barrier,
"root task allocation failed");
163 ~parallel_do_feeder_impl()
165 my_barrier->destroy(*my_barrier);
174 template<
typename Iterator,
typename Body,
typename Item>
175 class do_group_task_forward:
public task
177 static const size_t max_arg_size = 4;
179 typedef parallel_do_feeder_impl<Body, Item> feeder_type;
181 feeder_type& my_feeder;
185 do_group_task_forward( Iterator first,
size_t size, feeder_type& feeder )
186 : my_feeder(feeder), my_first(first), my_size(size)
191 typedef do_iteration_task_iter<Iterator, Body, Item> iteration_type;
192 __TBB_ASSERT( my_size>0, NULL );
197 t =
new( allocate_child() ) iteration_type( my_first, my_feeder );
199 if( ++k==my_size )
break;
202 set_ref_count(
int(k+1));
204 spawn_and_wait_for_all(*t);
208 template<
typename Iterator_,
typename Body_,
typename _Item>
friend class do_task_iter;
211 template<
typename Body,
typename Item>
212 class do_group_task_input:
public task
214 static const size_t max_arg_size = 4;
216 typedef parallel_do_feeder_impl<Body, Item> feeder_type;
218 feeder_type& my_feeder;
222 do_group_task_input( feeder_type& feeder )
223 : my_feeder(feeder), my_size(0)
228 typedef do_iteration_task_iter<Item*, Body, Item> iteration_type;
229 __TBB_ASSERT( my_size>0, NULL );
234 t =
new( allocate_child() ) iteration_type( my_arg.
begin() + k, my_feeder );
235 if( ++k==my_size )
break;
238 set_ref_count(
int(k+1));
240 spawn_and_wait_for_all(*t);
244 ~do_group_task_input(){
245 for(
size_t k=0; k<my_size; ++k)
246 (my_arg.
begin() + k)->~Item();
249 template<
typename Iterator_,
typename Body_,
typename Item_>
friend class do_task_iter;
255 template<
typename Iterator,
typename Body,
typename Item>
256 class do_task_iter:
public task
258 typedef parallel_do_feeder_impl<Body, Item> feeder_type;
261 do_task_iter( Iterator first, Iterator last , feeder_type& feeder ) :
262 my_first(first), my_last(last), my_feeder(feeder)
268 feeder_type& my_feeder;
282 typedef typename std::iterator_traits<Iterator>::iterator_category iterator_tag;
283 return run( (iterator_tag*)NULL );
288 inline task* run(
void* ) {
return run_for_input_iterator(); }
290 task* run_for_input_iterator() {
291 typedef do_group_task_input<Body, Item> block_type;
293 block_type& t = *
new( allocate_additional_child_of(*my_feeder.my_barrier) ) block_type(my_feeder);
295 while( !(my_first == my_last) ) {
297 new (t.my_arg.begin() + k) Item(*my_first);
299 if( ++k==block_type::max_arg_size ) {
300 if ( !(my_first == my_last) )
301 recycle_to_reexecute();
314 inline task* run( std::forward_iterator_tag* ) {
return run_for_forward_iterator(); }
316 task* run_for_forward_iterator() {
317 typedef do_group_task_forward<Iterator, Body, Item> block_type;
319 Iterator first = my_first;
321 while( !(my_first==my_last) ) {
323 if( ++k==block_type::max_arg_size ) {
324 if ( !(my_first==my_last) )
325 recycle_to_reexecute();
329 return k==0 ? NULL :
new( allocate_additional_child_of(*my_feeder.my_barrier) ) block_type(first, k, my_feeder);
332 inline task* run( std::random_access_iterator_tag* ) {
return run_for_random_access_iterator(); }
334 task* run_for_random_access_iterator() {
335 typedef do_group_task_forward<Iterator, Body, Item> block_type;
336 typedef do_iteration_task_iter<Iterator, Body, Item> iteration_type;
338 size_t k =
static_cast<size_t>(my_last-my_first);
339 if( k > block_type::max_arg_size ) {
340 Iterator middle = my_first + k/2;
342 empty_task& c = *
new( allocate_continuation() ) empty_task;
343 do_task_iter& b = *
new( c.allocate_child() ) do_task_iter(middle, my_last, my_feeder);
344 recycle_as_child_of(c);
355 t =
new( allocate_child() ) iteration_type(my_first, my_feeder);
360 set_ref_count(
int(k+1));
362 spawn_and_wait_for_all(*t);
371 template<
typename Iterator,
typename Body,
typename Item>
372 void run_parallel_do( Iterator first, Iterator last,
const Body& body
373 #
if __TBB_TASK_GROUP_CONTEXT
374 , task_group_context& context
378 typedef do_task_iter<Iterator, Body, Item> root_iteration_task;
379 #if __TBB_TASK_GROUP_CONTEXT 380 parallel_do_feeder_impl<Body, Item> feeder(context);
382 parallel_do_feeder_impl<Body, Item> feeder;
384 feeder.my_body = &body;
386 root_iteration_task &t = *
new( feeder.my_barrier->allocate_child() ) root_iteration_task(first, last, feeder);
388 feeder.my_barrier->set_ref_count(2);
389 feeder.my_barrier->spawn_and_wait_for_all(t);
395 template<
typename Iterator,
typename Body,
typename Item>
396 void select_parallel_do( Iterator first, Iterator last,
const Body& body,
void (Body::*)(Item)
const 397 #
if __TBB_TASK_GROUP_CONTEXT
398 , task_group_context& context
402 run_parallel_do<Iterator, Body, typename strip<Item>::type>( first, last, body
403 #if __TBB_TASK_GROUP_CONTEXT 405 #endif // __TBB_TASK_GROUP_CONTEXT 412 template<
typename Iterator,
typename Body,
typename Item,
typename _Item>
413 void select_parallel_do( Iterator first, Iterator last,
const Body& body,
void (Body::*)(Item,
parallel_do_feeder<_Item>&)
const 414 #
if __TBB_TASK_GROUP_CONTEXT
415 , task_group_context& context
419 run_parallel_do<Iterator, Body, typename strip<Item>::type>( first, last, body
420 #if __TBB_TASK_GROUP_CONTEXT 422 #endif // __TBB_TASK_GROUP_CONTEXT 454 template<
typename Iterator,
typename Body>
455 void parallel_do( Iterator first, Iterator last,
const Body& body )
459 #if __TBB_TASK_GROUP_CONTEXT 460 task_group_context context;
461 #endif // __TBB_TASK_GROUP_CONTEXT 462 internal::select_parallel_do( first, last, body, &Body::operator()
463 #
if __TBB_TASK_GROUP_CONTEXT
469 template<
typename Range,
typename Body>
471 parallel_do(tbb::internal::first(rng), tbb::internal::last(rng), body);
474 template<
typename Range,
typename Body>
475 void parallel_do(
const Range& rng,
const Body& body) {
476 parallel_do(tbb::internal::first(rng), tbb::internal::last(rng), body);
479 #if __TBB_TASK_GROUP_CONTEXT 482 template<
typename Iterator,
typename Body>
483 void parallel_do( Iterator first, Iterator last,
const Body& body, task_group_context& context )
487 internal::select_parallel_do( first, last, body, &Body::operator(), context );
490 template<
typename Range,
typename Body>
491 void parallel_do(Range& rng,
const Body& body, task_group_context& context) {
492 parallel_do(tbb::internal::first(rng), tbb::internal::last(rng), body, context);
495 template<
typename Range,
typename Body>
496 void parallel_do(
const Range& rng,
const Body& body, task_group_context& context) {
497 parallel_do(tbb::internal::first(rng), tbb::internal::last(rng), body, context);
500 #endif // __TBB_TASK_GROUP_CONTEXT void add(const Item &item)
Add a work item to a running parallel_do.
Definition: parallel_do.h:51
Block of space aligned sufficiently to construct an array T with N elements.
Definition: aligned_space.h:33
*/
Definition: material.h:665
T * begin()
Pointer to beginning of array.
Definition: aligned_space.h:39
Definition: _flow_graph_async_msg_impl.h:32
Class the user supplied algorithm body uses to add new tasks.
Definition: parallel_do.h:42
The namespace tbb contains all components of the library.
Definition: parallel_for.h:44
void parallel_do(Iterator first, Iterator last, const Body &body)
Parallel iteration over a range, with optional addition of more work.
Definition: parallel_do.h:455