Home ⌂Doc Index ◂Up ▴
Intel(R) Threading Building Blocks Doxygen Documentation  version 4.2.3
parallel_do.h
Go to the documentation of this file.
1 /*
2  Copyright (c) 2005-2020 Intel Corporation
3 
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7 
8  http://www.apache.org/licenses/LICENSE-2.0
9 
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 */
16 
17 #ifndef __TBB_parallel_do_H
18 #define __TBB_parallel_do_H
19 
20 #define __TBB_parallel_do_H_include_area
22 
25 #include "task.h"
26 #include "aligned_space.h"
27 #include <iterator>
28 
29 namespace tbb {
30 namespace interface9 {
32 namespace internal {
33  template<typename Body, typename Item> class parallel_do_feeder_impl;
34 } // namespace internal
36 
38 
39  template<typename Item>
41  {
43  virtual ~parallel_do_feeder () {}
44  virtual void internal_add_copy( const Item& item ) = 0;
45 #if __TBB_CPP11_RVALUE_REF_PRESENT
46  virtual void internal_add_move( Item&& item ) = 0;
47 #endif
48  template<typename Body_, typename Item_> friend class internal::parallel_do_feeder_impl;
49  public:
51  void add( const Item& item ) {internal_add_copy(item);}
52 #if __TBB_CPP11_RVALUE_REF_PRESENT
53  void add( Item&& item ) {internal_add_move(std::move(item));}
54 #endif
55  };
56 
58 namespace internal {
59  template<typename Body> class do_group_task;
60 
62 
64  template<class Body, typename Item>
66  {
68  template<typename A1, typename A2, typename CvItem >
69  static void internal_call( const Body& obj, __TBB_FORWARDING_REF(A1) arg1, A2&, void (Body::*)(CvItem) const ) {
70  obj(tbb::internal::forward<A1>(arg1));
71  }
72  template<typename A1, typename A2, typename CvItem >
73  static void internal_call( const Body& obj, __TBB_FORWARDING_REF(A1) arg1, A2& arg2, void (Body::*)(CvItem, parallel_do_feeder<Item>&) const ) {
74  obj(tbb::internal::forward<A1>(arg1), arg2);
75  }
76  template<typename A1, typename A2, typename CvItem >
77  static void internal_call( const Body& obj, __TBB_FORWARDING_REF(A1) arg1, A2&, void (Body::*)(CvItem&) const ) {
78  obj(arg1);
79  }
80  template<typename A1, typename A2, typename CvItem >
81  static void internal_call( const Body& obj, __TBB_FORWARDING_REF(A1) arg1, A2& arg2, void (Body::*)(CvItem&, parallel_do_feeder<Item>&) const ) {
82  obj(arg1, arg2);
83  }
84  public:
85  template<typename A1, typename A2>
86  static void call( const Body& obj, __TBB_FORWARDING_REF(A1) arg1, A2& arg2 )
87  {
88  internal_call( obj, tbb::internal::forward<A1>(arg1), arg2, &Body::operator() );
89  }
90  };
91 
93 
95  template<typename Body, typename Item>
96  class do_iteration_task: public task
97  {
99 
100  Item my_value;
102 
103  do_iteration_task( const Item& value, feeder_type& feeder ) :
104  my_value(value), my_feeder(feeder)
105  {}
106 
107 #if __TBB_CPP11_RVALUE_REF_PRESENT
108  do_iteration_task( Item&& value, feeder_type& feeder ) :
109  my_value(std::move(value)), my_feeder(feeder)
110  {}
111 #endif
112 
114  {
116  return NULL;
117  }
118 
119  template<typename Body_, typename Item_> friend class parallel_do_feeder_impl;
120  }; // class do_iteration_task
121 
122  template<typename Iterator, typename Body, typename Item>
124  {
126 
127  Iterator my_iter;
129 
130  do_iteration_task_iter( const Iterator& iter, feeder_type& feeder ) :
131  my_iter(iter), my_feeder(feeder)
132  {}
133 
135  {
137  return NULL;
138  }
139 
140  template<typename Iterator_, typename Body_, typename Item_> friend class do_group_task_forward;
141  template<typename Body_, typename Item_> friend class do_group_task_input;
142  template<typename Iterator_, typename Body_, typename Item_> friend class do_task_iter;
143  }; // class do_iteration_task_iter
144 
146 
148  template<class Body, typename Item>
149  class parallel_do_feeder_impl : public parallel_do_feeder<Item>
150  {
151 #if __TBB_CPP11_RVALUE_REF_PRESENT
152  //Avoiding use of copy constructor in a virtual method if the type does not support it
153  void internal_add_copy_impl(std::true_type, const Item& item) {
154  typedef do_iteration_task<Body, Item> iteration_type;
155  iteration_type& t = *new (task::allocate_additional_child_of(*my_barrier)) iteration_type(item, *this);
156  task::spawn(t);
157  }
159  __TBB_ASSERT(false, "Overloading for r-value reference doesn't work or it's not movable and not copyable object");
160  }
161  void internal_add_copy( const Item& item ) __TBB_override
162  {
163 #if __TBB_CPP11_IS_COPY_CONSTRUCTIBLE_PRESENT
165 #else
167 #endif
168  }
169  void internal_add_move( Item&& item ) __TBB_override
170  {
171  typedef do_iteration_task<Body, Item> iteration_type;
172  iteration_type& t = *new (task::allocate_additional_child_of(*my_barrier)) iteration_type(std::move(item), *this);
173  task::spawn(t);
174  }
175 #else /* ! __TBB_CPP11_RVALUE_REF_PRESENT */
176  void internal_add_copy(const Item& item) __TBB_override {
177  typedef do_iteration_task<Body, Item> iteration_type;
178  iteration_type& t = *new (task::allocate_additional_child_of(*my_barrier)) iteration_type(item, *this);
179  task::spawn(t);
180  }
181 #endif /* __TBB_CPP11_RVALUE_REF_PRESENT */
182  public:
183  const Body* my_body;
185 
187  {
189  __TBB_ASSERT(my_barrier, "root task allocation failed");
190  }
191 
192 #if __TBB_TASK_GROUP_CONTEXT
194  {
195  my_barrier = new( task::allocate_root(context) ) empty_task();
196  __TBB_ASSERT(my_barrier, "root task allocation failed");
197  }
198 #endif
199 
201  {
202  my_barrier->destroy(*my_barrier);
203  }
204  }; // class parallel_do_feeder_impl
205 
206 
208 
211  template<typename Iterator, typename Body, typename Item>
213  {
214  static const size_t max_arg_size = 4;
215 
217 
219  Iterator my_first;
220  size_t my_size;
221 
222  do_group_task_forward( Iterator first, size_t size, feeder_type& feeder )
223  : my_feeder(feeder), my_first(first), my_size(size)
224  {}
225 
227  {
228  typedef do_iteration_task_iter<Iterator, Body, Item> iteration_type;
229  __TBB_ASSERT( my_size>0, NULL );
230  task_list list;
231  task* t;
232  size_t k=0;
233  for(;;) {
234  t = new( allocate_child() ) iteration_type( my_first, my_feeder );
235  ++my_first;
236  if( ++k==my_size ) break;
237  list.push_back(*t);
238  }
239  set_ref_count(int(k+1));
240  spawn(list);
242  return NULL;
243  }
244 
245  template<typename Iterator_, typename Body_, typename _Item> friend class do_task_iter;
246  }; // class do_group_task_forward
247 
248  template<typename Body, typename Item>
249  class do_group_task_input: public task
250  {
251  static const size_t max_arg_size = 4;
252 
254 
256  size_t my_size;
257  aligned_space<Item, max_arg_size> my_arg;
258 
260  : my_feeder(feeder), my_size(0)
261  {}
262 
264  {
265 #if __TBB_CPP11_RVALUE_REF_PRESENT
266  typedef std::move_iterator<Item*> Item_iterator;
267 #else
268  typedef Item* Item_iterator;
269 #endif
271  __TBB_ASSERT( my_size>0, NULL );
272  task_list list;
273  task* t;
274  size_t k=0;
275  for(;;) {
276  t = new( allocate_child() ) iteration_type( Item_iterator(my_arg.begin() + k), my_feeder );
277  if( ++k==my_size ) break;
278  list.push_back(*t);
279  }
280  set_ref_count(int(k+1));
281  spawn(list);
283  return NULL;
284  }
285 
287  for( size_t k=0; k<my_size; ++k)
288  (my_arg.begin() + k)->~Item();
289  }
290 
291  template<typename Iterator_, typename Body_, typename Item_> friend class do_task_iter;
292  }; // class do_group_task_input
293 
295 
297  template<typename Iterator, typename Body, typename Item>
298  class do_task_iter: public task
299  {
301 
302  public:
303  do_task_iter( Iterator first, Iterator last , feeder_type& feeder ) :
304  my_first(first), my_last(last), my_feeder(feeder)
305  {}
306 
307  private:
308  Iterator my_first;
309  Iterator my_last;
311 
312  /* Do not merge run(xxx) and run_xxx() methods. They are separated in order
313  to make sure that compilers will eliminate unused argument of type xxx
314  (that is will not put it on stack). The sole purpose of this argument
315  is overload resolution.
316 
317  An alternative could be using template functions, but explicit specialization
318  of member function templates is not supported for non specialized class
319  templates. Besides template functions would always fall back to the least
320  efficient variant (the one for input iterators) in case of iterators having
321  custom tags derived from basic ones. */
323  {
324  typedef typename std::iterator_traits<Iterator>::iterator_category iterator_tag;
325  return run( (iterator_tag*)NULL );
326  }
327 
330  inline task* run( void* ) { return run_for_input_iterator(); }
331 
333  typedef do_group_task_input<Body, Item> block_type;
334 
335  block_type& t = *new( allocate_additional_child_of(*my_feeder.my_barrier) ) block_type(my_feeder);
336  size_t k=0;
337  while( !(my_first == my_last) ) {
338  // Move semantics are automatically used when supported by the iterator
339  new (t.my_arg.begin() + k) Item(*my_first);
340  ++my_first;
341  if( ++k==block_type::max_arg_size ) {
342  if ( !(my_first == my_last) )
344  break;
345  }
346  }
347  if( k==0 ) {
348  destroy(t);
349  return NULL;
350  } else {
351  t.my_size = k;
352  return &t;
353  }
354  }
355 
356  inline task* run( std::forward_iterator_tag* ) { return run_for_forward_iterator(); }
357 
360 
361  Iterator first = my_first;
362  size_t k=0;
363  while( !(my_first==my_last) ) {
364  ++my_first;
365  if( ++k==block_type::max_arg_size ) {
366  if ( !(my_first==my_last) )
368  break;
369  }
370  }
371  return k==0 ? NULL : new( allocate_additional_child_of(*my_feeder.my_barrier) ) block_type(first, k, my_feeder);
372  }
373 
374  inline task* run( std::random_access_iterator_tag* ) { return run_for_random_access_iterator(); }
375 
378  typedef do_iteration_task_iter<Iterator, Body, Item> iteration_type;
379 
380  size_t k = static_cast<size_t>(my_last-my_first);
381  if( k > block_type::max_arg_size ) {
382  Iterator middle = my_first + k/2;
383 
385  do_task_iter& b = *new( c.allocate_child() ) do_task_iter(middle, my_last, my_feeder);
387 
388  my_last = middle;
389  c.set_ref_count(2);
390  c.spawn(b);
391  return this;
392  }else if( k != 0 ) {
393  task_list list;
394  task* t;
395  size_t k1=0;
396  for(;;) {
397  t = new( allocate_child() ) iteration_type(my_first, my_feeder);
398  ++my_first;
399  if( ++k1==k ) break;
400  list.push_back(*t);
401  }
402  set_ref_count(int(k+1));
403  spawn(list);
405  }
406  return NULL;
407  }
408  }; // class do_task_iter
409 
411 
413  template<typename Iterator, typename Body, typename Item>
414  void run_parallel_do( Iterator first, Iterator last, const Body& body
416  , task_group_context& context
417 #endif
418  )
419  {
420  typedef do_task_iter<Iterator, Body, Item> root_iteration_task;
421 #if __TBB_TASK_GROUP_CONTEXT
422  parallel_do_feeder_impl<Body, Item> feeder(context);
423 #else
425 #endif
426  feeder.my_body = &body;
427 
428  root_iteration_task &t = *new( feeder.my_barrier->allocate_child() ) root_iteration_task(first, last, feeder);
429 
430  feeder.my_barrier->set_ref_count(2);
431  feeder.my_barrier->spawn_and_wait_for_all(t);
432  }
433 
435 
437  template<typename Iterator, typename Body, typename Item>
438  void select_parallel_do( Iterator first, Iterator last, const Body& body, void (Body::*)(Item) const
440  , task_group_context& context
441 #endif
442  )
443  {
445 #if __TBB_TASK_GROUP_CONTEXT
446  , context
447 #endif
448  );
449  }
450 
452 
454  template<typename Iterator, typename Body, typename Item, typename _Item>
455  void select_parallel_do( Iterator first, Iterator last, const Body& body, void (Body::*)(Item, parallel_do_feeder<_Item>&) const
457  , task_group_context& context
458 #endif
459  )
460  {
462 #if __TBB_TASK_GROUP_CONTEXT
463  , context
464 #endif
465  );
466  }
467 
468 } // namespace internal
469 } // namespace interface9
471 
494 
496 template<typename Iterator, typename Body>
497 void parallel_do( Iterator first, Iterator last, const Body& body )
498 {
499  if ( first == last )
500  return;
501 #if __TBB_TASK_GROUP_CONTEXT
502  task_group_context context(internal::PARALLEL_DO);
503 #endif
504  interface9::internal::select_parallel_do( first, last, body, &Body::operator()
506  , context
507 #endif
508  );
509 }
510 
511 template<typename Range, typename Body>
512 void parallel_do(Range& rng, const Body& body) {
514 }
515 
516 template<typename Range, typename Body>
517 void parallel_do(const Range& rng, const Body& body) {
519 }
520 
521 #if __TBB_TASK_GROUP_CONTEXT
522 
524 template<typename Iterator, typename Body>
525 void parallel_do( Iterator first, Iterator last, const Body& body, task_group_context& context )
526 {
527  if ( first == last )
528  return;
529  interface9::internal::select_parallel_do( first, last, body, &Body::operator(), context );
530 }
531 
532 template<typename Range, typename Body>
533 void parallel_do(Range& rng, const Body& body, task_group_context& context) {
534  parallel_do(tbb::internal::first(rng), tbb::internal::last(rng), body, context);
535 }
536 
537 template<typename Range, typename Body>
538 void parallel_do(const Range& rng, const Body& body, task_group_context& context) {
539  parallel_do(tbb::internal::first(rng), tbb::internal::last(rng), body, context);
540 }
541 
542 #endif // __TBB_TASK_GROUP_CONTEXT
543 
545 
546 using interface9::parallel_do_feeder;
547 
548 } // namespace
549 
551 #undef __TBB_parallel_do_H_include_area
552 
553 #endif /* __TBB_parallel_do_H */
bool_constant< true > true_type
Definition: tbb_stddef.h:489
do_group_task_forward(Iterator first, size_t size, feeder_type &feeder)
Definition: parallel_do.h:222
void recycle_to_reexecute()
Schedule this for reexecution after current execute() returns.
Definition: task.h:741
Used to form groups of tasks.
Definition: task.h:358
void spawn_and_wait_for_all(task &child)
Similar to spawn followed by wait_for_all, but more efficient.
Definition: task.h:800
do_iteration_task(Item &&value, feeder_type &feeder)
Definition: parallel_do.h:108
void push_back(task &task)
Push task onto back of list.
Definition: task.h:1091
#define __TBB_TASK_GROUP_CONTEXT
Definition: tbb_config.h:541
A list of children.
Definition: task.h:1074
Base class for user-defined tasks.
Definition: task.h:615
task * execute() __TBB_override
Should be overridden by derived classes.
Definition: parallel_do.h:226
parallel_do_feeder_impl< Body, Item > feeder_type
Definition: parallel_do.h:125
Class the user supplied algorithm body uses to add new tasks.
Definition: parallel_do.h:40
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p void ITT_FORMAT p no args __itt_suppress_mode_t unsigned int void size_t size
task * execute() __TBB_override
Should be overridden by derived classes.
Definition: parallel_do.h:134
void internal_add_move(Item &&item) __TBB_override
Definition: parallel_do.h:169
void select_parallel_do(Iterator first, Iterator last, const Body &body, void(Body::*)(Item) const, task_group_context &context)
For internal use only.
Definition: parallel_do.h:438
static void call(const Body &obj, __TBB_FORWARDING_REF(A1) arg1, A2 &arg2)
Definition: parallel_do.h:86
static void internal_call(const Body &obj, __TBB_FORWARDING_REF(A1) arg1, A2 &arg2, void(Body::*)(CvItem, parallel_do_feeder< Item > &) const)
Definition: parallel_do.h:73
auto last(Container &c) -> decltype(begin(c))
bool_constant< false > false_type
Definition: tbb_stddef.h:490
task * execute() __TBB_override
Should be overridden by derived classes.
Definition: parallel_do.h:113
static internal::allocate_root_proxy allocate_root()
Returns proxy for overloaded new that allocates a root task.
Definition: task.h:663
static void internal_call(const Body &obj, __TBB_FORWARDING_REF(A1) arg1, A2 &, void(Body::*)(CvItem) const)
Definition: parallel_do.h:69
task * execute() __TBB_override
Should be overridden by derived classes.
Definition: parallel_do.h:322
internal::allocate_child_proxy & allocate_child()
Returns proxy for overloaded new that allocates a child task of *this.
Definition: task.h:681
internal::allocate_continuation_proxy & allocate_continuation()
Returns proxy for overloaded new that allocates a continuation task of *this.
Definition: task.h:676
task that does nothing. Useful for synchronization.
Definition: task.h:1042
static void internal_call(const Body &obj, __TBB_FORWARDING_REF(A1) arg1, A2 &, void(Body::*)(CvItem &) const)
Definition: parallel_do.h:77
virtual void internal_add_copy(const Item &item)=0
void recycle_as_child_of(task &new_parent)
Change this to be a child of new_parent.
Definition: task.h:725
parallel_do_feeder_impl< Body, Item > feeder_type
Definition: parallel_do.h:300
Base class for types that should not be copied or assigned.
Definition: tbb_stddef.h:330
void internal_add_copy(const Item &item) __TBB_override
Definition: parallel_do.h:161
void set_ref_count(int count)
Set reference count.
Definition: task.h:761
do_iteration_task_iter(const Iterator &iter, feeder_type &feeder)
Definition: parallel_do.h:130
task * execute() __TBB_override
Should be overridden by derived classes.
Definition: parallel_do.h:263
void internal_add_copy_impl(std::false_type, const Item &)
Definition: parallel_do.h:158
auto first(Container &c) -> decltype(begin(c))
parallel_do_feeder_impl< Body, Item > feeder_type
Definition: parallel_do.h:98
#define __TBB_override
Definition: tbb_stddef.h:240
void internal_add_copy_impl(std::true_type, const Item &item)
Definition: parallel_do.h:153
void add(const Item &item)
Add a work item to a running parallel_do.
Definition: parallel_do.h:51
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:497
static void internal_call(const Body &obj, __TBB_FORWARDING_REF(A1) arg1, A2 &arg2, void(Body::*)(CvItem &, parallel_do_feeder< Item > &) const)
Definition: parallel_do.h:81
parallel_do_feeder_impl< Body, Item > feeder_type
Definition: parallel_do.h:216
parallel_do_feeder_impl< Body, Item > feeder_type
Definition: parallel_do.h:253
#define __TBB_FORWARDING_REF(A)
Definition: tbb_stddef.h:517
#define __TBB_ASSERT(predicate, comment)
No-op version of __TBB_ASSERT.
Definition: tbb_stddef.h:165
task * run(std::forward_iterator_tag *)
Definition: parallel_do.h:356
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p void ITT_FORMAT p no args __itt_suppress_mode_t unsigned int void size_t ITT_FORMAT d void ITT_FORMAT p void ITT_FORMAT p __itt_model_site __itt_model_site_instance ITT_FORMAT p __itt_model_task __itt_model_task_instance ITT_FORMAT p void ITT_FORMAT p void ITT_FORMAT p void size_t ITT_FORMAT d void ITT_FORMAT p const wchar_t ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s no args void ITT_FORMAT p size_t ITT_FORMAT d no args const wchar_t const wchar_t ITT_FORMAT s __itt_heap_function void size_t int ITT_FORMAT d __itt_heap_function void ITT_FORMAT p __itt_heap_function void void size_t int ITT_FORMAT d no args no args unsigned int ITT_FORMAT u const __itt_domain __itt_id ITT_FORMAT lu const __itt_domain __itt_id __itt_id __itt_string_handle ITT_FORMAT p const __itt_domain __itt_id ITT_FORMAT p const __itt_domain __itt_id __itt_timestamp __itt_timestamp ITT_FORMAT lu const __itt_domain __itt_id __itt_id __itt_string_handle ITT_FORMAT p const __itt_domain ITT_FORMAT p const __itt_domain __itt_string_handle unsigned long long value
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p void ITT_FORMAT p no args __itt_suppress_mode_t unsigned int void size_t ITT_FORMAT d void ITT_FORMAT p void ITT_FORMAT p __itt_model_site __itt_model_site_instance ITT_FORMAT p __itt_model_task __itt_model_task_instance ITT_FORMAT p void ITT_FORMAT p void ITT_FORMAT p void size_t ITT_FORMAT d void ITT_FORMAT p const wchar_t ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s no args void ITT_FORMAT p size_t ITT_FORMAT d no args const wchar_t const wchar_t ITT_FORMAT s __itt_heap_function void size_t int ITT_FORMAT d __itt_heap_function void ITT_FORMAT p __itt_heap_function void void size_t int ITT_FORMAT d no args no args unsigned int ITT_FORMAT u const __itt_domain __itt_id ITT_FORMAT lu const __itt_domain __itt_id __itt_id __itt_string_handle ITT_FORMAT p const __itt_domain __itt_id ITT_FORMAT p const __itt_domain __itt_id __itt_timestamp __itt_timestamp ITT_FORMAT lu const __itt_domain __itt_id __itt_id __itt_string_handle ITT_FORMAT p const __itt_domain ITT_FORMAT p const __itt_domain __itt_string_handle unsigned long long ITT_FORMAT lu const __itt_domain __itt_string_handle unsigned long long ITT_FORMAT lu const __itt_domain __itt_id __itt_string_handle __itt_metadata_type type
The graph class.
do_iteration_task(const Item &value, feeder_type &feeder)
Definition: parallel_do.h:103
aligned_space< Item, max_arg_size > my_arg
Definition: parallel_do.h:257
virtual void internal_add_move(Item &&item)=0
void run_parallel_do(Iterator first, Iterator last, const Body &body, task_group_context &context)
For internal use only.
Definition: parallel_do.h:414
do_task_iter(Iterator first, Iterator last, feeder_type &feeder)
Definition: parallel_do.h:303
parallel_do_feeder_impl(tbb::task_group_context &context)
Definition: parallel_do.h:193
task * run(std::random_access_iterator_tag *)
Definition: parallel_do.h:374
void move(tbb_thread &t1, tbb_thread &t2)
Definition: tbb_thread.h:319

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