Intel(R) Threading Building Blocks Doxygen Documentation version 4.2.3
Loading...
Searching...
No Matches
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
29namespace tbb {
30namespace interface9 {
32namespace 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
58namespace 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
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
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>
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 }
158 void internal_add_copy_impl(std::false_type, const Item&) {
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
164 internal_add_copy_impl(typename std::is_copy_constructible<Item>::type(), item);
165#else
166 internal_add_copy_impl(std::true_type(), item);
167#endif
168 }
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 {
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>
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 ) :
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
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
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);
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 {
444 run_parallel_do<Iterator, Body, typename ::tbb::internal::strip<Item>::type>( first, last, body
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 {
461 run_parallel_do<Iterator, Body, typename ::tbb::internal::strip<Item>::type>( first, last, body
462#if __TBB_TASK_GROUP_CONTEXT
463 , context
464#endif
465 );
466 }
467
468} // namespace internal
469} // namespace interface9
471
495
496template<typename Iterator, typename Body>
497void 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
511template<typename Range, typename Body>
512void parallel_do(Range& rng, const Body& body) {
514}
515
516template<typename Range, typename Body>
517void parallel_do(const Range& rng, const Body& body) {
519}
520
521#if __TBB_TASK_GROUP_CONTEXT
523
524template<typename Iterator, typename Body>
525void 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
532template<typename Range, typename Body>
533void 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
537template<typename Range, typename Body>
538void 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
546using interface9::parallel_do_feeder;
547
548} // namespace
549
551#undef __TBB_parallel_do_H_include_area
552
553#endif /* __TBB_parallel_do_H */
#define __TBB_TASK_GROUP_CONTEXT
Definition tbb_config.h:541
#define __TBB_ASSERT(predicate, comment)
No-op version of __TBB_ASSERT.
Definition tbb_stddef.h:165
#define __TBB_override
Definition tbb_stddef.h:240
#define __TBB_FORWARDING_REF(A)
Definition tbb_stddef.h:517
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 size
void parallel_do(Iterator first, Iterator last, const Body &body)
Parallel iteration over a range, with optional addition of more work.
void run_parallel_do(Iterator first, Iterator last, const Body &body, task_group_context &context)
For internal use only.
void select_parallel_do(Iterator first, Iterator last, const Body &body, void(Body::*)(Item) const, task_group_context &context)
For internal use only.
STL namespace.
The graph class.
void move(tbb_thread &t1, tbb_thread &t2)
Definition tbb_thread.h:319
auto last(Container &c) -> decltype(begin(c))
auto first(Container &c) -> decltype(begin(c))
void internal_add_move(Item &&item) __TBB_override
parallel_do_feeder_impl(tbb::task_group_context &context)
void internal_add_copy_impl(std::false_type, const Item &)
void internal_add_copy_impl(std::true_type, const Item &item)
void internal_add_copy(const Item &item) __TBB_override
Class the user supplied algorithm body uses to add new tasks.
Definition parallel_do.h:41
void add(const Item &item)
Add a work item to a running parallel_do.
Definition parallel_do.h:51
virtual void internal_add_move(Item &&item)=0
virtual void internal_add_copy(const Item &item)=0
static void internal_call(const Body &obj, __TBB_FORWARDING_REF(A1) arg1, A2 &, void(Body::*)(CvItem) const)
Definition parallel_do.h:69
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
static void internal_call(const Body &obj, __TBB_FORWARDING_REF(A1) arg1, A2 &, void(Body::*)(CvItem &) const)
Definition parallel_do.h:77
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
static void call(const Body &obj, __TBB_FORWARDING_REF(A1) arg1, A2 &arg2)
Definition parallel_do.h:86
task * execute() __TBB_override
Should be overridden by derived classes.
do_iteration_task(Item &&value, feeder_type &feeder)
parallel_do_feeder_impl< Body, Item > feeder_type
Definition parallel_do.h:98
do_iteration_task(const Item &value, feeder_type &feeder)
parallel_do_feeder_impl< Body, Item > feeder_type
do_iteration_task_iter(const Iterator &iter, feeder_type &feeder)
task * execute() __TBB_override
Should be overridden by derived classes.
parallel_do_feeder_impl< Body, Item > feeder_type
task * execute() __TBB_override
Should be overridden by derived classes.
do_group_task_forward(Iterator first, size_t size, feeder_type &feeder)
aligned_space< Item, max_arg_size > my_arg
parallel_do_feeder_impl< Body, Item > feeder_type
task * execute() __TBB_override
Should be overridden by derived classes.
do_task_iter(Iterator first, Iterator last, feeder_type &feeder)
task * run(std::random_access_iterator_tag *)
task * run(std::forward_iterator_tag *)
task * execute() __TBB_override
Should be overridden by derived classes.
parallel_do_feeder_impl< Body, Item > feeder_type
Used to form groups of tasks.
Definition task.h:358
Base class for user-defined tasks.
Definition task.h:615
internal::allocate_child_proxy & allocate_child()
Returns proxy for overloaded new that allocates a child task of *this.
Definition task.h:681
void recycle_to_reexecute()
Schedule this for reexecution after current execute() returns.
Definition task.h:741
internal::allocate_continuation_proxy & allocate_continuation()
Returns proxy for overloaded new that allocates a continuation task of *this.
Definition task.h:676
void recycle_as_child_of(task &new_parent)
Change this to be a child of new_parent.
Definition task.h:725
void spawn_and_wait_for_all(task &child)
Similar to spawn followed by wait_for_all, but more efficient.
Definition task.h:800
static internal::allocate_root_proxy allocate_root()
Returns proxy for overloaded new that allocates a root task.
Definition task.h:663
void set_ref_count(int count)
Set reference count.
Definition task.h:761
task that does nothing. Useful for synchronization.
Definition task.h:1042
A list of children.
Definition task.h:1077
void push_back(task &task)
Push task onto back of list.
Definition task.h:1094
Base class for types that should not be copied or assigned.
Definition tbb_stddef.h:330

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.