00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #ifndef __TBB_flow_graph_H
00022 #define __TBB_flow_graph_H
00023
00024 #include "tbb_stddef.h"
00025 #include "atomic.h"
00026 #include "spin_mutex.h"
00027 #include "null_mutex.h"
00028 #include "spin_rw_mutex.h"
00029 #include "null_rw_mutex.h"
00030 #include "task.h"
00031 #include "concurrent_vector.h"
00032 #include "internal/_aggregator_impl.h"
00033
00034
00035 #if __TBB_CPP11_TUPLE_PRESENT
00036 #include <tuple>
00037 namespace tbb {
00038 namespace flow {
00039 using std::tuple;
00040 using std::tuple_size;
00041 using std::tuple_element;
00042 using std::get;
00043 }
00044 }
00045 #else
00046 #include "compat/tuple"
00047 #endif
00048
00049 #include<list>
00050 #include<queue>
00051
00062 namespace tbb {
00063 namespace flow {
00064
00066 enum concurrency { unlimited = 0, serial = 1 };
00067
00068 namespace interface6 {
00069
00070 namespace internal {
00071 template<typename T, typename M> class successor_cache;
00072 template<typename T, typename M> class broadcast_cache;
00073 template<typename T, typename M> class round_robin_cache;
00074 }
00075
00077 class continue_msg {};
00078
00079 template< typename T > class sender;
00080 template< typename T > class receiver;
00081 class continue_receiver;
00082
00084 template< typename T >
00085 class sender {
00086 public:
00088 typedef T output_type;
00089
00091 typedef receiver<T> successor_type;
00092
00093 virtual ~sender() {}
00094
00096 virtual bool register_successor( successor_type &r ) = 0;
00097
00099 virtual bool remove_successor( successor_type &r ) = 0;
00100
00102 virtual bool try_get( T & ) { return false; }
00103
00105 virtual bool try_reserve( T & ) { return false; }
00106
00108 virtual bool try_release( ) { return false; }
00109
00111 virtual bool try_consume( ) { return false; }
00112 };
00113
00114 template< typename T > class limiter_node;
00115 template< typename R, typename B > class run_and_put_task;
00116
00117 static tbb::task * const SUCCESSFULLY_ENQUEUED = (task *)-1;
00118
00119
00120 static inline tbb::task *combine_tasks( tbb::task * left, tbb::task * right) {
00121
00122 if(right == NULL) return left;
00123
00124 if(left == NULL) return right;
00125 if(left == SUCCESSFULLY_ENQUEUED) return right;
00126
00127 if(right != SUCCESSFULLY_ENQUEUED) {
00128
00129 tbb::task::enqueue(*left);
00130 return right;
00131 }
00132 return left;
00133 }
00134
00136 template< typename T >
00137 class receiver {
00138 public:
00140 typedef T input_type;
00141
00143 typedef sender<T> predecessor_type;
00144
00146 virtual ~receiver() {}
00147
00149 bool try_put( const T& t ) {
00150 task *res = try_put_task(t);
00151 if(!res) return false;
00152 if (res != SUCCESSFULLY_ENQUEUED) task::enqueue(*res);
00153 return true;
00154 }
00155
00157 protected:
00158 template< typename R, typename B > friend class run_and_put_task;
00159 template<typename X, typename Y> friend class internal::broadcast_cache;
00160 template<typename X, typename Y> friend class internal::round_robin_cache;
00161 virtual task *try_put_task(const T& t) = 0;
00162 public:
00163
00165 virtual bool register_predecessor( predecessor_type & ) { return false; }
00166
00168 virtual bool remove_predecessor( predecessor_type & ) { return false; }
00169
00170 protected:
00172 template<typename U> friend class limiter_node;
00173 virtual void reset_receiver() = 0;
00174
00175 template<typename TT, typename M>
00176 friend class internal::successor_cache;
00177 virtual bool is_continue_receiver() { return false; }
00178 };
00179
00181
00182 class continue_receiver : public receiver< continue_msg > {
00183 public:
00184
00186 typedef continue_msg input_type;
00187
00189 typedef sender< continue_msg > predecessor_type;
00190
00192 continue_receiver( int number_of_predecessors = 0 ) {
00193 my_predecessor_count = my_initial_predecessor_count = number_of_predecessors;
00194 my_current_count = 0;
00195 }
00196
00198 continue_receiver( const continue_receiver& src ) : receiver<continue_msg>() {
00199 my_predecessor_count = my_initial_predecessor_count = src.my_initial_predecessor_count;
00200 my_current_count = 0;
00201 }
00202
00204 virtual ~continue_receiver() { }
00205
00207 bool register_predecessor( predecessor_type & ) {
00208 spin_mutex::scoped_lock l(my_mutex);
00209 ++my_predecessor_count;
00210 return true;
00211 }
00212
00214
00217 bool remove_predecessor( predecessor_type & ) {
00218 spin_mutex::scoped_lock l(my_mutex);
00219 --my_predecessor_count;
00220 return true;
00221 }
00222
00223 protected:
00224 template< typename R, typename B > friend class run_and_put_task;
00225 template<typename X, typename Y> friend class internal::broadcast_cache;
00226 template<typename X, typename Y> friend class internal::round_robin_cache;
00227
00228 task *try_put_task( const input_type & ) {
00229 {
00230 spin_mutex::scoped_lock l(my_mutex);
00231 if ( ++my_current_count < my_predecessor_count )
00232 return SUCCESSFULLY_ENQUEUED;
00233 else
00234 my_current_count = 0;
00235 }
00236 task * res = execute();
00237 return res;
00238 }
00239
00240 spin_mutex my_mutex;
00241 int my_predecessor_count;
00242 int my_current_count;
00243 int my_initial_predecessor_count;
00244
00245
00246 template<typename U> friend class limiter_node;
00247 void reset_receiver() {
00248 my_current_count = 0;
00249 }
00250
00252
00254 virtual task * execute() = 0;
00255 template<typename TT, typename M>
00256 friend class internal::successor_cache;
00257 bool is_continue_receiver() { return true; }
00258 };
00259
00260 #include "internal/_flow_graph_impl.h"
00261 using namespace internal::graph_policy_namespace;
00262
00263 class graph;
00264 class graph_node;
00265
00266 template <typename GraphContainerType, typename GraphNodeType>
00267 class graph_iterator {
00268 friend class graph;
00269 friend class graph_node;
00270 public:
00271 typedef size_t size_type;
00272 typedef GraphNodeType value_type;
00273 typedef GraphNodeType* pointer;
00274 typedef GraphNodeType& reference;
00275 typedef const GraphNodeType& const_reference;
00276 typedef std::forward_iterator_tag iterator_category;
00277
00279 graph_iterator() : my_graph(NULL), current_node(NULL) {}
00280
00282 graph_iterator(const graph_iterator& other) :
00283 my_graph(other.my_graph), current_node(other.current_node)
00284 {}
00285
00287 graph_iterator& operator=(const graph_iterator& other) {
00288 if (this != &other) {
00289 my_graph = other.my_graph;
00290 current_node = other.current_node;
00291 }
00292 return *this;
00293 }
00294
00296 reference operator*() const;
00297
00299 pointer operator->() const;
00300
00302 bool operator==(const graph_iterator& other) const {
00303 return ((my_graph == other.my_graph) && (current_node == other.current_node));
00304 }
00305
00307 bool operator!=(const graph_iterator& other) const { return !(operator==(other)); }
00308
00310 graph_iterator& operator++() {
00311 internal_forward();
00312 return *this;
00313 }
00314
00316 graph_iterator operator++(int) {
00317 graph_iterator result = *this;
00318 operator++();
00319 return result;
00320 }
00321
00322 private:
00323
00324 GraphContainerType *my_graph;
00325
00326 pointer current_node;
00327
00329 graph_iterator(GraphContainerType *g, bool begin);
00330 void internal_forward();
00331 };
00332
00334
00335 class graph : tbb::internal::no_copy {
00336 friend class graph_node;
00337
00338 template< typename Body >
00339 class run_task : public task {
00340 public:
00341 run_task( Body& body ) : my_body(body) {}
00342 task *execute() {
00343 my_body();
00344 return NULL;
00345 }
00346 private:
00347 Body my_body;
00348 };
00349
00350 template< typename Receiver, typename Body >
00351 class run_and_put_task : public task {
00352 public:
00353 run_and_put_task( Receiver &r, Body& body ) : my_receiver(r), my_body(body) {}
00354 task *execute() {
00355 task *res = my_receiver.try_put_task( my_body() );
00356 if(res == SUCCESSFULLY_ENQUEUED) res = NULL;
00357 return res;
00358 }
00359 private:
00360 Receiver &my_receiver;
00361 Body my_body;
00362 };
00363
00364 public:
00366 explicit graph() : my_nodes(NULL), my_nodes_last(NULL)
00367 {
00368 own_context = true;
00369 cancelled = false;
00370 caught_exception = false;
00371 my_context = new task_group_context();
00372 my_root_task = ( new ( task::allocate_root(*my_context) ) empty_task );
00373 my_root_task->set_ref_count(1);
00374 }
00375
00377 explicit graph(task_group_context& use_this_context) :
00378 my_context(&use_this_context), my_nodes(NULL), my_nodes_last(NULL)
00379 {
00380 own_context = false;
00381 my_root_task = ( new ( task::allocate_root(*my_context) ) empty_task );
00382 my_root_task->set_ref_count(1);
00383 }
00384
00386
00387 ~graph() {
00388 wait_for_all();
00389 my_root_task->set_ref_count(0);
00390 task::destroy( *my_root_task );
00391 if (own_context) delete my_context;
00392 }
00393
00395
00397 void increment_wait_count() {
00398 if (my_root_task)
00399 my_root_task->increment_ref_count();
00400 }
00401
00403
00405 void decrement_wait_count() {
00406 if (my_root_task)
00407 my_root_task->decrement_ref_count();
00408 }
00409
00411
00413 template< typename Receiver, typename Body >
00414 void run( Receiver &r, Body body ) {
00415 task::enqueue( * new ( task::allocate_additional_child_of( *my_root_task ) )
00416 run_and_put_task< Receiver, Body >( r, body ) );
00417 }
00418
00420
00422 template< typename Body >
00423 void run( Body body ) {
00424 task::enqueue( * new ( task::allocate_additional_child_of( *my_root_task ) )
00425 run_task< Body >( body ) );
00426 }
00427
00429
00430 void wait_for_all() {
00431 cancelled = false;
00432 caught_exception = false;
00433 if (my_root_task) {
00434 #if TBB_USE_EXCEPTIONS
00435 try {
00436 #endif
00437 my_root_task->wait_for_all();
00438 cancelled = my_context->is_group_execution_cancelled();
00439 #if TBB_USE_EXCEPTIONS
00440 }
00441 catch(...) {
00442 my_root_task->set_ref_count(1);
00443 my_context->reset();
00444 caught_exception = true;
00445 cancelled = true;
00446 throw;
00447 }
00448 #endif
00449 my_context->reset();
00450 my_root_task->set_ref_count(1);
00451 }
00452 }
00453
00455 task * root_task() {
00456 return my_root_task;
00457 }
00458
00459
00460 template<typename C, typename N>
00461 friend class graph_iterator;
00462
00463
00464 typedef graph_iterator<graph,graph_node> iterator;
00465 typedef graph_iterator<const graph,const graph_node> const_iterator;
00466
00467
00469 iterator begin() { return iterator(this, true); }
00471 iterator end() { return iterator(this, false); }
00473 const_iterator begin() const { return const_iterator(this, true); }
00475 const_iterator end() const { return const_iterator(this, false); }
00477 const_iterator cbegin() const { return const_iterator(this, true); }
00479 const_iterator cend() const { return const_iterator(this, false); }
00480
00482 bool is_cancelled() { return cancelled; }
00483 bool exception_thrown() { return caught_exception; }
00484
00485
00486 void reset();
00487
00488 private:
00489 task *my_root_task;
00490 task_group_context *my_context;
00491 bool own_context;
00492 bool cancelled;
00493 bool caught_exception;
00494
00495 graph_node *my_nodes, *my_nodes_last;
00496
00497 spin_mutex nodelist_mutex;
00498 void register_node(graph_node *n);
00499 void remove_node(graph_node *n);
00500
00501 };
00502
00503 template <typename C, typename N>
00504 graph_iterator<C,N>::graph_iterator(C *g, bool begin) : my_graph(g), current_node(NULL)
00505 {
00506 if (begin) current_node = my_graph->my_nodes;
00507
00508 }
00509
00510 template <typename C, typename N>
00511 typename graph_iterator<C,N>::reference graph_iterator<C,N>::operator*() const {
00512 __TBB_ASSERT(current_node, "graph_iterator at end");
00513 return *operator->();
00514 }
00515
00516 template <typename C, typename N>
00517 typename graph_iterator<C,N>::pointer graph_iterator<C,N>::operator->() const {
00518 return current_node;
00519 }
00520
00521
00522 template <typename C, typename N>
00523 void graph_iterator<C,N>::internal_forward() {
00524 if (current_node) current_node = current_node->next;
00525 }
00526
00528 class graph_node : tbb::internal::no_assign {
00529 friend class graph;
00530 template<typename C, typename N>
00531 friend class graph_iterator;
00532 protected:
00533 graph& my_graph;
00534 graph_node *next, *prev;
00535 public:
00536 graph_node(graph& g) : my_graph(g) {
00537 my_graph.register_node(this);
00538 }
00539 virtual ~graph_node() {
00540 my_graph.remove_node(this);
00541 }
00542
00543 protected:
00544 virtual void reset() = 0;
00545 };
00546
00547 inline void graph::register_node(graph_node *n) {
00548 n->next = NULL;
00549 {
00550 spin_mutex::scoped_lock lock(nodelist_mutex);
00551 n->prev = my_nodes_last;
00552 if (my_nodes_last) my_nodes_last->next = n;
00553 my_nodes_last = n;
00554 if (!my_nodes) my_nodes = n;
00555 }
00556 }
00557
00558 inline void graph::remove_node(graph_node *n) {
00559 {
00560 spin_mutex::scoped_lock lock(nodelist_mutex);
00561 __TBB_ASSERT(my_nodes && my_nodes_last, "graph::remove_node: Error: no registered nodes");
00562 if (n->prev) n->prev->next = n->next;
00563 if (n->next) n->next->prev = n->prev;
00564 if (my_nodes_last == n) my_nodes_last = n->prev;
00565 if (my_nodes == n) my_nodes = n->next;
00566 }
00567 n->prev = n->next = NULL;
00568 }
00569
00570 inline void graph::reset() {
00571
00572 if(my_context) my_context->reset();
00573 cancelled = false;
00574 caught_exception = false;
00575
00576 for(iterator ii = begin(); ii != end(); ++ii) {
00577 graph_node *my_p = &(*ii);
00578 my_p->reset();
00579 }
00580 }
00581
00582
00583 #include "internal/_flow_graph_node_impl.h"
00584
00586 template < typename Output >
00587 class source_node : public graph_node, public sender< Output > {
00588 protected:
00589 using graph_node::my_graph;
00590 public:
00592 typedef Output output_type;
00593
00595 typedef receiver< Output > successor_type;
00596
00598 template< typename Body >
00599 source_node( graph &g, Body body, bool is_active = true )
00600 : graph_node(g), my_root_task(g.root_task()), my_active(is_active), init_my_active(is_active),
00601 my_body( new internal::source_body_leaf< output_type, Body>(body) ),
00602 my_reserved(false), my_has_cached_item(false)
00603 {
00604 my_successors.set_owner(this);
00605 }
00606
00608 source_node( const source_node& src ) :
00609 graph_node(src.my_graph), sender<Output>(),
00610 my_root_task( src.my_root_task), my_active(src.init_my_active),
00611 init_my_active(src.init_my_active), my_body( src.my_body->clone() ),
00612 my_reserved(false), my_has_cached_item(false)
00613 {
00614 my_successors.set_owner(this);
00615 }
00616
00618 ~source_node() { delete my_body; }
00619
00621 bool register_successor( receiver<output_type> &r ) {
00622 spin_mutex::scoped_lock lock(my_mutex);
00623 my_successors.register_successor(r);
00624 if ( my_active )
00625 spawn_put();
00626 return true;
00627 }
00628
00630 bool remove_successor( receiver<output_type> &r ) {
00631 spin_mutex::scoped_lock lock(my_mutex);
00632 my_successors.remove_successor(r);
00633 return true;
00634 }
00635
00637 bool try_get( output_type &v ) {
00638 spin_mutex::scoped_lock lock(my_mutex);
00639 if ( my_reserved )
00640 return false;
00641
00642 if ( my_has_cached_item ) {
00643 v = my_cached_item;
00644 my_has_cached_item = false;
00645 return true;
00646 }
00647 return false;
00648 }
00649
00651 bool try_reserve( output_type &v ) {
00652 spin_mutex::scoped_lock lock(my_mutex);
00653 if ( my_reserved ) {
00654 return false;
00655 }
00656
00657 if ( my_has_cached_item ) {
00658 v = my_cached_item;
00659 my_reserved = true;
00660 return true;
00661 } else {
00662 return false;
00663 }
00664 }
00665
00667
00668 bool try_release( ) {
00669 spin_mutex::scoped_lock lock(my_mutex);
00670 __TBB_ASSERT( my_reserved && my_has_cached_item, "releasing non-existent reservation" );
00671 my_reserved = false;
00672 if(!my_successors.empty())
00673 spawn_put();
00674 return true;
00675 }
00676
00678 bool try_consume( ) {
00679 spin_mutex::scoped_lock lock(my_mutex);
00680 __TBB_ASSERT( my_reserved && my_has_cached_item, "consuming non-existent reservation" );
00681 my_reserved = false;
00682 my_has_cached_item = false;
00683 if ( !my_successors.empty() ) {
00684 spawn_put();
00685 }
00686 return true;
00687 }
00688
00690 void activate() {
00691 spin_mutex::scoped_lock lock(my_mutex);
00692 my_active = true;
00693 if ( !my_successors.empty() )
00694 spawn_put();
00695 }
00696
00697 template<typename Body>
00698 Body copy_function_object() {
00699 internal::source_body<output_type> &body_ref = *this->my_body;
00700 return dynamic_cast< internal::source_body_leaf<output_type, Body> & >(body_ref).get_body();
00701 }
00702
00703 protected:
00704
00706 void reset() {
00707 my_active = init_my_active;
00708 my_reserved =false;
00709 if(my_has_cached_item) {
00710 my_has_cached_item = false;
00711 }
00712 }
00713
00714 private:
00715 task *my_root_task;
00716 spin_mutex my_mutex;
00717 bool my_active;
00718 bool init_my_active;
00719 internal::source_body<output_type> *my_body;
00720 internal::broadcast_cache< output_type > my_successors;
00721 bool my_reserved;
00722 bool my_has_cached_item;
00723 output_type my_cached_item;
00724
00725
00726 bool try_reserve_apply_body(output_type &v) {
00727 spin_mutex::scoped_lock lock(my_mutex);
00728 if ( my_reserved ) {
00729 return false;
00730 }
00731 if ( !my_has_cached_item && (*my_body)(my_cached_item) )
00732 my_has_cached_item = true;
00733 if ( my_has_cached_item ) {
00734 v = my_cached_item;
00735 my_reserved = true;
00736 return true;
00737 } else {
00738 return false;
00739 }
00740 }
00741
00743 void spawn_put( ) {
00744 task::enqueue( * new ( task::allocate_additional_child_of( *my_root_task ) )
00745 internal:: source_task_bypass < source_node< output_type > >( *this ) );
00746 }
00747
00748 friend class internal::source_task_bypass< source_node< output_type > >;
00750 task * apply_body_bypass( ) {
00751 output_type v;
00752 if ( !try_reserve_apply_body(v) )
00753 return NULL;
00754
00755 task *last_task = my_successors.try_put_task(v);
00756 if ( last_task )
00757 try_consume();
00758 else
00759 try_release();
00760 return last_task;
00761 }
00762 };
00763
00765 template < typename Input, typename Output = continue_msg, graph_buffer_policy = queueing, typename Allocator=cache_aligned_allocator<Input> >
00766 class function_node : public graph_node, public internal::function_input<Input,Output,Allocator>, public internal::function_output<Output> {
00767 protected:
00768 using graph_node::my_graph;
00769 public:
00770 typedef Input input_type;
00771 typedef Output output_type;
00772 typedef sender< input_type > predecessor_type;
00773 typedef receiver< output_type > successor_type;
00774 typedef internal::function_input<input_type,output_type,Allocator> fInput_type;
00775 typedef internal::function_output<output_type> fOutput_type;
00776
00778 template< typename Body >
00779 function_node( graph &g, size_t concurrency, Body body ) :
00780 graph_node(g), internal::function_input<input_type,output_type,Allocator>(g, concurrency, body)
00781 {}
00782
00784 function_node( const function_node& src ) :
00785 graph_node(src.my_graph), internal::function_input<input_type,output_type,Allocator>( src ),
00786 fOutput_type()
00787 {}
00788
00789 protected:
00790 template< typename R, typename B > friend class run_and_put_task;
00791 template<typename X, typename Y> friend class internal::broadcast_cache;
00792 template<typename X, typename Y> friend class internal::round_robin_cache;
00793 using fInput_type::try_put_task;
00794
00795
00796 void reset() {fInput_type::reset_function_input(); }
00797
00798 internal::broadcast_cache<output_type> &successors () { return fOutput_type::my_successors; }
00799 };
00800
00802 template < typename Input, typename Output, typename Allocator >
00803 class function_node<Input,Output,queueing,Allocator> : public graph_node, public internal::function_input<Input,Output,Allocator>, public internal::function_output<Output> {
00804 protected:
00805 using graph_node::my_graph;
00806 public:
00807 typedef Input input_type;
00808 typedef Output output_type;
00809 typedef sender< input_type > predecessor_type;
00810 typedef receiver< output_type > successor_type;
00811 typedef internal::function_input<input_type,output_type,Allocator> fInput_type;
00812 typedef internal::function_input_queue<input_type, Allocator> queue_type;
00813 typedef internal::function_output<output_type> fOutput_type;
00814
00816 template< typename Body >
00817 function_node( graph &g, size_t concurrency, Body body ) :
00818 graph_node(g), fInput_type( g, concurrency, body, new queue_type() )
00819 {}
00820
00822 function_node( const function_node& src ) :
00823 graph_node(src.my_graph), fInput_type( src, new queue_type() ), fOutput_type()
00824 {}
00825
00826 protected:
00827 template< typename R, typename B > friend class run_and_put_task;
00828 template<typename X, typename Y> friend class internal::broadcast_cache;
00829 template<typename X, typename Y> friend class internal::round_robin_cache;
00830 using fInput_type::try_put_task;
00831
00832 void reset() { fInput_type::reset_function_input(); }
00833
00834 internal::broadcast_cache<output_type> &successors () { return fOutput_type::my_successors; }
00835 };
00836
00837 #include "tbb/internal/_flow_graph_types_impl.h"
00838
00840
00841 template < typename Input, typename Output, graph_buffer_policy = queueing, typename Allocator=cache_aligned_allocator<Input> >
00842 class multifunction_node :
00843 public graph_node,
00844 public internal::multifunction_input
00845 <
00846 Input,
00847 typename internal::wrap_tuple_elements<
00848 tbb::flow::tuple_size<Output>::value,
00849 internal::multifunction_output,
00850 Output
00851 >::type,
00852 Allocator
00853 > {
00854 protected:
00855 using graph_node::my_graph;
00856 private:
00857 static const int N = tbb::flow::tuple_size<Output>::value;
00858 public:
00859 typedef Input input_type;
00860 typedef typename internal::wrap_tuple_elements<N,internal::multifunction_output, Output>::type output_ports_type;
00861 private:
00862 typedef typename internal::multifunction_input<input_type, output_ports_type, Allocator> base_type;
00863 typedef typename internal::function_input_queue<input_type,Allocator> queue_type;
00864 public:
00865 template<typename Body>
00866 multifunction_node( graph &g, size_t concurrency, Body body ) :
00867 graph_node(g), base_type(g,concurrency, body)
00868 {}
00869 multifunction_node( const multifunction_node &other) :
00870 graph_node(other.my_graph), base_type(other)
00871 {}
00872
00873 protected:
00874 void reset() { base_type::reset(); }
00875 };
00876
00877 template < typename Input, typename Output, typename Allocator >
00878 class multifunction_node<Input,Output,queueing,Allocator> : public graph_node, public internal::multifunction_input<Input,
00879 typename internal::wrap_tuple_elements<tbb::flow::tuple_size<Output>::value, internal::multifunction_output, Output>::type, Allocator> {
00880 protected:
00881 using graph_node::my_graph;
00882 static const int N = tbb::flow::tuple_size<Output>::value;
00883 public:
00884 typedef Input input_type;
00885 typedef typename internal::wrap_tuple_elements<N, internal::multifunction_output, Output>::type output_ports_type;
00886 private:
00887 typedef typename internal::multifunction_input<input_type, output_ports_type, Allocator> base_type;
00888 typedef typename internal::function_input_queue<input_type,Allocator> queue_type;
00889 public:
00890 template<typename Body>
00891 multifunction_node( graph &g, size_t concurrency, Body body) :
00892 graph_node(g), base_type(g,concurrency, body, new queue_type())
00893 {}
00894 multifunction_node( const multifunction_node &other) :
00895 graph_node(other.my_graph), base_type(other, new queue_type())
00896 {}
00897
00898 protected:
00899 void reset() { base_type::reset(); }
00900 };
00901
00903
00904
00905 template<typename TupleType, typename Allocator=cache_aligned_allocator<TupleType> >
00906 class split_node : public multifunction_node<TupleType, TupleType, rejecting, Allocator> {
00907 static const int N = tbb::flow::tuple_size<TupleType>::value;
00908 typedef multifunction_node<TupleType,TupleType,rejecting,Allocator> base_type;
00909 public:
00910 typedef typename base_type::output_ports_type output_ports_type;
00911 private:
00912 struct splitting_body {
00913 void operator()(const TupleType& t, output_ports_type &p) {
00914 internal::emit_element<N>::emit_this(t, p);
00915 }
00916 };
00917 public:
00918 typedef TupleType input_type;
00919 typedef Allocator allocator_type;
00920 split_node(graph &g) : base_type(g, unlimited, splitting_body()) {}
00921 split_node( const split_node & other) : base_type(other) {}
00922 };
00923
00925 template <typename Output>
00926 class continue_node : public graph_node, public internal::continue_input<Output>, public internal::function_output<Output> {
00927 protected:
00928 using graph_node::my_graph;
00929 public:
00930 typedef continue_msg input_type;
00931 typedef Output output_type;
00932 typedef sender< input_type > predecessor_type;
00933 typedef receiver< output_type > successor_type;
00934 typedef internal::continue_input<Output> fInput_type;
00935 typedef internal::function_output<output_type> fOutput_type;
00936
00938 template <typename Body >
00939 continue_node( graph &g, Body body ) :
00940 graph_node(g), internal::continue_input<output_type>( g, body )
00941 {}
00942
00944 template <typename Body >
00945 continue_node( graph &g, int number_of_predecessors, Body body ) :
00946 graph_node(g), internal::continue_input<output_type>( g, number_of_predecessors, body )
00947 {}
00948
00950 continue_node( const continue_node& src ) :
00951 graph_node(src.my_graph), internal::continue_input<output_type>(src),
00952 internal::function_output<Output>()
00953 {}
00954
00955 protected:
00956 template< typename R, typename B > friend class run_and_put_task;
00957 template<typename X, typename Y> friend class internal::broadcast_cache;
00958 template<typename X, typename Y> friend class internal::round_robin_cache;
00959 using fInput_type::try_put_task;
00960
00961 void reset() { internal::continue_input<Output>::reset_receiver(); }
00962
00963 internal::broadcast_cache<output_type> &successors () { return fOutput_type::my_successors; }
00964 };
00965
00966 template< typename T >
00967 class overwrite_node : public graph_node, public receiver<T>, public sender<T> {
00968 protected:
00969 using graph_node::my_graph;
00970 public:
00971 typedef T input_type;
00972 typedef T output_type;
00973 typedef sender< input_type > predecessor_type;
00974 typedef receiver< output_type > successor_type;
00975
00976 overwrite_node(graph &g) : graph_node(g), my_buffer_is_valid(false) {
00977 my_successors.set_owner( this );
00978 }
00979
00980
00981 overwrite_node( const overwrite_node& src ) :
00982 graph_node(src.my_graph), receiver<T>(), sender<T>(), my_buffer_is_valid(false)
00983 {
00984 my_successors.set_owner( this );
00985 }
00986
00987 ~overwrite_node() {}
00988
00989 bool register_successor( successor_type &s ) {
00990 spin_mutex::scoped_lock l( my_mutex );
00991 if ( my_buffer_is_valid ) {
00992
00993 if ( s.try_put( my_buffer ) || !s.register_predecessor( *this ) ) {
00994
00995 my_successors.register_successor( s );
00996 return true;
00997 } else {
00998
00999 return false;
01000 }
01001 } else {
01002
01003 my_successors.register_successor( s );
01004 return true;
01005 }
01006 }
01007
01008 bool remove_successor( successor_type &s ) {
01009 spin_mutex::scoped_lock l( my_mutex );
01010 my_successors.remove_successor(s);
01011 return true;
01012 }
01013
01014 bool try_get( T &v ) {
01015 spin_mutex::scoped_lock l( my_mutex );
01016 if ( my_buffer_is_valid ) {
01017 v = my_buffer;
01018 return true;
01019 } else {
01020 return false;
01021 }
01022 }
01023
01024 bool is_valid() {
01025 spin_mutex::scoped_lock l( my_mutex );
01026 return my_buffer_is_valid;
01027 }
01028
01029 void clear() {
01030 spin_mutex::scoped_lock l( my_mutex );
01031 my_buffer_is_valid = false;
01032 }
01033
01034 protected:
01035 template< typename R, typename B > friend class run_and_put_task;
01036 template<typename X, typename Y> friend class internal::broadcast_cache;
01037 template<typename X, typename Y> friend class internal::round_robin_cache;
01038 task * try_put_task( const T &v ) {
01039 spin_mutex::scoped_lock l( my_mutex );
01040 my_buffer = v;
01041 my_buffer_is_valid = true;
01042 task * rtask = my_successors.try_put_task(v);
01043 if(!rtask) rtask = SUCCESSFULLY_ENQUEUED;
01044 return rtask;
01045 }
01046
01047 void reset() { my_buffer_is_valid = false; }
01048
01049 spin_mutex my_mutex;
01050 internal::broadcast_cache< T, null_rw_mutex > my_successors;
01051 T my_buffer;
01052 bool my_buffer_is_valid;
01053 void reset_receiver() {}
01054 };
01055
01056 template< typename T >
01057 class write_once_node : public overwrite_node<T> {
01058 public:
01059 typedef T input_type;
01060 typedef T output_type;
01061 typedef sender< input_type > predecessor_type;
01062 typedef receiver< output_type > successor_type;
01063
01065 write_once_node(graph& g) : overwrite_node<T>(g) {}
01066
01068 write_once_node( const write_once_node& src ) : overwrite_node<T>(src) {}
01069
01070 protected:
01071 template< typename R, typename B > friend class run_and_put_task;
01072 template<typename X, typename Y> friend class internal::broadcast_cache;
01073 template<typename X, typename Y> friend class internal::round_robin_cache;
01074 task *try_put_task( const T &v ) {
01075 spin_mutex::scoped_lock l( this->my_mutex );
01076 if ( this->my_buffer_is_valid ) {
01077 return NULL;
01078 } else {
01079 this->my_buffer = v;
01080 this->my_buffer_is_valid = true;
01081 task *res = this->my_successors.try_put_task(v);
01082 if(!res) res = SUCCESSFULLY_ENQUEUED;
01083 return res;
01084 }
01085 }
01086 };
01087
01089 template <typename T>
01090 class broadcast_node : public graph_node, public receiver<T>, public sender<T> {
01091 protected:
01092 using graph_node::my_graph;
01093 private:
01094 internal::broadcast_cache<T> my_successors;
01095 public:
01096 typedef T input_type;
01097 typedef T output_type;
01098 typedef sender< input_type > predecessor_type;
01099 typedef receiver< output_type > successor_type;
01100
01101 broadcast_node(graph& g) : graph_node(g) {
01102 my_successors.set_owner( this );
01103 }
01104
01105
01106 broadcast_node( const broadcast_node& src ) :
01107 graph_node(src.my_graph), receiver<T>(), sender<T>()
01108 {
01109 my_successors.set_owner( this );
01110 }
01111
01113 virtual bool register_successor( receiver<T> &r ) {
01114 my_successors.register_successor( r );
01115 return true;
01116 }
01117
01119 virtual bool remove_successor( receiver<T> &r ) {
01120 my_successors.remove_successor( r );
01121 return true;
01122 }
01123
01124 protected:
01125 template< typename R, typename B > friend class run_and_put_task;
01126 template<typename X, typename Y> friend class internal::broadcast_cache;
01127 template<typename X, typename Y> friend class internal::round_robin_cache;
01129 task *try_put_task(const T& t) {
01130 task *new_task = my_successors.try_put_task(t);
01131 if(!new_task) new_task = SUCCESSFULLY_ENQUEUED;
01132 return new_task;
01133 }
01134
01135 void reset() {}
01136 void reset_receiver() {}
01137 };
01138
01139 #include "internal/_flow_graph_item_buffer_impl.h"
01140
01142 template <typename T, typename A=cache_aligned_allocator<T> >
01143 class buffer_node : public graph_node, public reservable_item_buffer<T, A>, public receiver<T>, public sender<T> {
01144 protected:
01145 using graph_node::my_graph;
01146 public:
01147 typedef T input_type;
01148 typedef T output_type;
01149 typedef sender< input_type > predecessor_type;
01150 typedef receiver< output_type > successor_type;
01151 typedef buffer_node<T, A> my_class;
01152 protected:
01153 typedef size_t size_type;
01154 internal::round_robin_cache< T, null_rw_mutex > my_successors;
01155
01156 task *my_parent;
01157
01158 friend class internal::forward_task_bypass< buffer_node< T, A > >;
01159
01160 enum op_type {reg_succ, rem_succ, req_item, res_item, rel_res, con_res, put_item, try_fwd_task };
01161 enum op_stat {WAIT=0, SUCCEEDED, FAILED};
01162
01163
01164 class buffer_operation : public internal::aggregated_operation< buffer_operation > {
01165 public:
01166 char type;
01167 T *elem;
01168 task * ltask;
01169 successor_type *r;
01170 buffer_operation(const T& e, op_type t) : type(char(t)), elem(const_cast<T*>(&e)) , ltask(NULL) , r(NULL) {}
01171 buffer_operation(op_type t) : type(char(t)) , ltask(NULL) , r(NULL) {}
01172 };
01173
01174 bool forwarder_busy;
01175 typedef internal::aggregating_functor<my_class, buffer_operation> my_handler;
01176 friend class internal::aggregating_functor<my_class, buffer_operation>;
01177 internal::aggregator< my_handler, buffer_operation> my_aggregator;
01178
01179 virtual void handle_operations(buffer_operation *op_list) {
01180 buffer_operation *tmp = NULL;
01181 bool try_forwarding=false;
01182 while (op_list) {
01183 tmp = op_list;
01184 op_list = op_list->next;
01185 switch (tmp->type) {
01186 case reg_succ: internal_reg_succ(tmp); try_forwarding = true; break;
01187 case rem_succ: internal_rem_succ(tmp); break;
01188 case req_item: internal_pop(tmp); break;
01189 case res_item: internal_reserve(tmp); break;
01190 case rel_res: internal_release(tmp); try_forwarding = true; break;
01191 case con_res: internal_consume(tmp); try_forwarding = true; break;
01192 case put_item: internal_push(tmp); try_forwarding = true; break;
01193 case try_fwd_task: internal_forward_task(tmp); break;
01194 }
01195 }
01196 if (try_forwarding && !forwarder_busy) {
01197 forwarder_busy = true;
01198 task *new_task = new(task::allocate_additional_child_of(*my_parent)) internal::
01199 forward_task_bypass
01200 < buffer_node<input_type, A> >(*this);
01201
01202
01203 tbb::task *z = tmp->ltask;
01204 tmp->ltask = combine_tasks(z, new_task);
01205 }
01206 }
01207
01208 inline task *grab_forwarding_task( buffer_operation &op_data) {
01209 return op_data.ltask;
01210 }
01211
01212 inline bool enqueue_forwarding_task(buffer_operation &op_data) {
01213 task *ft = grab_forwarding_task(op_data);
01214 if(ft) {
01215 task::enqueue(*ft);
01216 return true;
01217 }
01218 return false;
01219 }
01220
01222 virtual task *forward_task() {
01223 buffer_operation op_data(try_fwd_task);
01224 task *last_task = NULL;
01225 do {
01226 op_data.status = WAIT;
01227 op_data.ltask = NULL;
01228 my_aggregator.execute(&op_data);
01229 tbb::task *xtask = op_data.ltask;
01230 last_task = combine_tasks(last_task, xtask);
01231 } while (op_data.status == SUCCEEDED);
01232 return last_task;
01233 }
01234
01236 virtual void internal_reg_succ(buffer_operation *op) {
01237 my_successors.register_successor(*(op->r));
01238 __TBB_store_with_release(op->status, SUCCEEDED);
01239 }
01240
01242 virtual void internal_rem_succ(buffer_operation *op) {
01243 my_successors.remove_successor(*(op->r));
01244 __TBB_store_with_release(op->status, SUCCEEDED);
01245 }
01246
01248 virtual void internal_forward_task(buffer_operation *op) {
01249 if (this->my_reserved || !this->item_valid(this->my_tail-1)) {
01250 __TBB_store_with_release(op->status, FAILED);
01251 this->forwarder_busy = false;
01252 return;
01253 }
01254 T i_copy;
01255 task * last_task = NULL;
01256 size_type counter = my_successors.size();
01257
01258 while (counter>0 && !this->buffer_empty() && this->item_valid(this->my_tail-1)) {
01259 this->fetch_back(i_copy);
01260 task *new_task = my_successors.try_put_task(i_copy);
01261 last_task = combine_tasks(last_task, new_task);
01262 if(new_task) {
01263 this->invalidate_back();
01264 --(this->my_tail);
01265 }
01266 --counter;
01267 }
01268 op->ltask = last_task;
01269 if (last_task && !counter) {
01270 __TBB_store_with_release(op->status, SUCCEEDED);
01271 }
01272 else {
01273 __TBB_store_with_release(op->status, FAILED);
01274 forwarder_busy = false;
01275 }
01276 }
01277
01278 virtual void internal_push(buffer_operation *op) {
01279 this->push_back(*(op->elem));
01280 __TBB_store_with_release(op->status, SUCCEEDED);
01281 }
01282
01283 virtual void internal_pop(buffer_operation *op) {
01284 if(this->pop_back(*(op->elem))) {
01285 __TBB_store_with_release(op->status, SUCCEEDED);
01286 }
01287 else {
01288 __TBB_store_with_release(op->status, FAILED);
01289 }
01290 }
01291
01292 virtual void internal_reserve(buffer_operation *op) {
01293 if(this->reserve_front(*(op->elem))) {
01294 __TBB_store_with_release(op->status, SUCCEEDED);
01295 }
01296 else {
01297 __TBB_store_with_release(op->status, FAILED);
01298 }
01299 }
01300
01301 virtual void internal_consume(buffer_operation *op) {
01302 this->consume_front();
01303 __TBB_store_with_release(op->status, SUCCEEDED);
01304 }
01305
01306 virtual void internal_release(buffer_operation *op) {
01307 this->release_front();
01308 __TBB_store_with_release(op->status, SUCCEEDED);
01309 }
01310
01311 public:
01313 buffer_node( graph &g ) : graph_node(g), reservable_item_buffer<T>(),
01314 my_parent( g.root_task() ), forwarder_busy(false) {
01315 my_successors.set_owner(this);
01316 my_aggregator.initialize_handler(my_handler(this));
01317 }
01318
01320 buffer_node( const buffer_node& src ) : graph_node(src.my_graph),
01321 reservable_item_buffer<T>(), receiver<T>(), sender<T>(),
01322 my_parent( src.my_parent ) {
01323 forwarder_busy = false;
01324 my_successors.set_owner(this);
01325 my_aggregator.initialize_handler(my_handler(this));
01326 }
01327
01328 virtual ~buffer_node() {}
01329
01330
01331
01332
01333
01335
01336 bool register_successor( receiver<output_type> &r ) {
01337 buffer_operation op_data(reg_succ);
01338 op_data.r = &r;
01339 my_aggregator.execute(&op_data);
01340 (void)enqueue_forwarding_task(op_data);
01341 return true;
01342 }
01343
01345
01347 bool remove_successor( receiver<output_type> &r ) {
01348 r.remove_predecessor(*this);
01349 buffer_operation op_data(rem_succ);
01350 op_data.r = &r;
01351 my_aggregator.execute(&op_data);
01352
01353
01354
01355 (void)enqueue_forwarding_task(op_data);
01356 return true;
01357 }
01358
01360
01362 bool try_get( T &v ) {
01363 buffer_operation op_data(req_item);
01364 op_data.elem = &v;
01365 my_aggregator.execute(&op_data);
01366 (void)enqueue_forwarding_task(op_data);
01367 return (op_data.status==SUCCEEDED);
01368 }
01369
01371
01373 bool try_reserve( T &v ) {
01374 buffer_operation op_data(res_item);
01375 op_data.elem = &v;
01376 my_aggregator.execute(&op_data);
01377 (void)enqueue_forwarding_task(op_data);
01378 return (op_data.status==SUCCEEDED);
01379 }
01380
01382
01383 bool try_release() {
01384 buffer_operation op_data(rel_res);
01385 my_aggregator.execute(&op_data);
01386 (void)enqueue_forwarding_task(op_data);
01387 return true;
01388 }
01389
01391
01392 bool try_consume() {
01393 buffer_operation op_data(con_res);
01394 my_aggregator.execute(&op_data);
01395 (void)enqueue_forwarding_task(op_data);
01396 return true;
01397 }
01398
01399 protected:
01400
01401 template< typename R, typename B > friend class run_and_put_task;
01402 template<typename X, typename Y> friend class internal::broadcast_cache;
01403 template<typename X, typename Y> friend class internal::round_robin_cache;
01405 task *try_put_task(const T &t) {
01406 buffer_operation op_data(t, put_item);
01407 my_aggregator.execute(&op_data);
01408 task *ft = grab_forwarding_task(op_data);
01409 if(!ft) {
01410 ft = SUCCESSFULLY_ENQUEUED;
01411 }
01412 return ft;
01413 }
01414
01415 void reset() {
01416 reservable_item_buffer<T, A>::reset();
01417 forwarder_busy = false;
01418 }
01419
01420 void reset_receiver() {
01421
01422 }
01423
01424 };
01425
01427 template <typename T, typename A=cache_aligned_allocator<T> >
01428 class queue_node : public buffer_node<T, A> {
01429 protected:
01430 typedef typename buffer_node<T, A>::size_type size_type;
01431 typedef typename buffer_node<T, A>::buffer_operation queue_operation;
01432
01433 enum op_stat {WAIT=0, SUCCEEDED, FAILED};
01434
01435 void internal_forward_task(queue_operation *op) {
01436 if (this->my_reserved || !this->item_valid(this->my_head)) {
01437 __TBB_store_with_release(op->status, FAILED);
01438 this->forwarder_busy = false;
01439 return;
01440 }
01441 T i_copy;
01442 task *last_task = NULL;
01443 size_type counter = this->my_successors.size();
01444
01445 while (counter>0 && this->item_valid(this->my_head)) {
01446 this->fetch_front(i_copy);
01447 task *new_task = this->my_successors.try_put_task(i_copy);
01448 if(new_task) {
01449 this->invalidate_front();
01450 ++(this->my_head);
01451 last_task = combine_tasks(last_task, new_task);
01452 }
01453 --counter;
01454 }
01455 op->ltask = last_task;
01456 if (last_task && !counter)
01457 __TBB_store_with_release(op->status, SUCCEEDED);
01458 else {
01459 __TBB_store_with_release(op->status, FAILED);
01460 this->forwarder_busy = false;
01461 }
01462 }
01463
01464 void internal_pop(queue_operation *op) {
01465 if ( this->my_reserved || !this->item_valid(this->my_head)){
01466 __TBB_store_with_release(op->status, FAILED);
01467 }
01468 else {
01469 this->pop_front(*(op->elem));
01470 __TBB_store_with_release(op->status, SUCCEEDED);
01471 }
01472 }
01473 void internal_reserve(queue_operation *op) {
01474 if (this->my_reserved || !this->item_valid(this->my_head)) {
01475 __TBB_store_with_release(op->status, FAILED);
01476 }
01477 else {
01478 this->my_reserved = true;
01479 this->fetch_front(*(op->elem));
01480 this->invalidate_front();
01481 __TBB_store_with_release(op->status, SUCCEEDED);
01482 }
01483 }
01484 void internal_consume(queue_operation *op) {
01485 this->consume_front();
01486 __TBB_store_with_release(op->status, SUCCEEDED);
01487 }
01488
01489 public:
01490 typedef T input_type;
01491 typedef T output_type;
01492 typedef sender< input_type > predecessor_type;
01493 typedef receiver< output_type > successor_type;
01494
01496 queue_node( graph &g ) : buffer_node<T, A>(g) {}
01497
01499 queue_node( const queue_node& src) : buffer_node<T, A>(src) {}
01500 };
01501
01503 template< typename T, typename A=cache_aligned_allocator<T> >
01504 class sequencer_node : public queue_node<T, A> {
01505 internal::function_body< T, size_t > *my_sequencer;
01506 public:
01507 typedef T input_type;
01508 typedef T output_type;
01509 typedef sender< input_type > predecessor_type;
01510 typedef receiver< output_type > successor_type;
01511
01513 template< typename Sequencer >
01514 sequencer_node( graph &g, const Sequencer& s ) : queue_node<T, A>(g),
01515 my_sequencer(new internal::function_body_leaf< T, size_t, Sequencer>(s) ) {}
01516
01518 sequencer_node( const sequencer_node& src ) : queue_node<T, A>(src),
01519 my_sequencer( src.my_sequencer->clone() ) {}
01520
01522 ~sequencer_node() { delete my_sequencer; }
01523 protected:
01524 typedef typename buffer_node<T, A>::size_type size_type;
01525 typedef typename buffer_node<T, A>::buffer_operation sequencer_operation;
01526
01527 enum op_stat {WAIT=0, SUCCEEDED, FAILED};
01528
01529 private:
01530 void internal_push(sequencer_operation *op) {
01531 size_type tag = (*my_sequencer)(*(op->elem));
01532
01533 this->my_tail = (tag+1 > this->my_tail) ? tag+1 : this->my_tail;
01534
01535 if(this->size() > this->capacity())
01536 this->grow_my_array(this->size());
01537 this->item(tag) = std::make_pair( *(op->elem), true );
01538 __TBB_store_with_release(op->status, SUCCEEDED);
01539 }
01540 };
01541
01543 template< typename T, typename Compare = std::less<T>, typename A=cache_aligned_allocator<T> >
01544 class priority_queue_node : public buffer_node<T, A> {
01545 public:
01546 typedef T input_type;
01547 typedef T output_type;
01548 typedef buffer_node<T,A> base_type;
01549 typedef sender< input_type > predecessor_type;
01550 typedef receiver< output_type > successor_type;
01551
01553 priority_queue_node( graph &g ) : buffer_node<T, A>(g), mark(0) {}
01554
01556 priority_queue_node( const priority_queue_node &src ) : buffer_node<T, A>(src), mark(0) {}
01557
01558 protected:
01559
01560 void reset() {
01561 mark = 0;
01562 base_type::reset();
01563 }
01564
01565 typedef typename buffer_node<T, A>::size_type size_type;
01566 typedef typename buffer_node<T, A>::item_type item_type;
01567 typedef typename buffer_node<T, A>::buffer_operation prio_operation;
01568
01569 enum op_stat {WAIT=0, SUCCEEDED, FAILED};
01570
01571 void handle_operations(prio_operation *op_list) {
01572 prio_operation *tmp = op_list ;
01573 bool try_forwarding=false;
01574 while (op_list) {
01575 tmp = op_list;
01576 op_list = op_list->next;
01577 switch (tmp->type) {
01578 case buffer_node<T, A>::reg_succ: this->internal_reg_succ(tmp); try_forwarding = true; break;
01579 case buffer_node<T, A>::rem_succ: this->internal_rem_succ(tmp); break;
01580 case buffer_node<T, A>::put_item: internal_push(tmp); try_forwarding = true; break;
01581 case buffer_node<T, A>::try_fwd_task: internal_forward_task(tmp); break;
01582 case buffer_node<T, A>::rel_res: internal_release(tmp); try_forwarding = true; break;
01583 case buffer_node<T, A>::con_res: internal_consume(tmp); try_forwarding = true; break;
01584 case buffer_node<T, A>::req_item: internal_pop(tmp); break;
01585 case buffer_node<T, A>::res_item: internal_reserve(tmp); break;
01586 }
01587 }
01588
01589 if (mark<this->my_tail) heapify();
01590 if (try_forwarding && !this->forwarder_busy) {
01591 this->forwarder_busy = true;
01592 task *new_task = new(task::allocate_additional_child_of(*(this->my_parent))) internal::
01593 forward_task_bypass
01594 < buffer_node<input_type, A> >(*this);
01595
01596
01597 tbb::task *tmp1 = tmp->ltask;
01598 tmp->ltask = combine_tasks(tmp1, new_task);
01599 }
01600 }
01601
01603 void internal_forward_task(prio_operation *op) {
01604 T i_copy;
01605 task * last_task = NULL;
01606 size_type counter = this->my_successors.size();
01607
01608 if (this->my_reserved || this->my_tail == 0) {
01609 __TBB_store_with_release(op->status, FAILED);
01610 this->forwarder_busy = false;
01611 return;
01612 }
01613
01614 while (counter>0 && this->my_tail > 0) {
01615 i_copy = this->my_array[0].first;
01616 task * new_task = this->my_successors.try_put_task(i_copy);
01617 last_task = combine_tasks(last_task, new_task);
01618 if ( new_task ) {
01619 if (mark == this->my_tail) --mark;
01620 --(this->my_tail);
01621 this->my_array[0].first=this->my_array[this->my_tail].first;
01622 if (this->my_tail > 1)
01623 reheap();
01624 }
01625 --counter;
01626 }
01627 op->ltask = last_task;
01628 if (last_task && !counter)
01629 __TBB_store_with_release(op->status, SUCCEEDED);
01630 else {
01631 __TBB_store_with_release(op->status, FAILED);
01632 this->forwarder_busy = false;
01633 }
01634 }
01635
01636 void internal_push(prio_operation *op) {
01637 if ( this->my_tail >= this->my_array_size )
01638 this->grow_my_array( this->my_tail + 1 );
01639 this->my_array[this->my_tail] = std::make_pair( *(op->elem), true );
01640 ++(this->my_tail);
01641 __TBB_store_with_release(op->status, SUCCEEDED);
01642 }
01643
01644 void internal_pop(prio_operation *op) {
01645 if ( this->my_reserved == true || this->my_tail == 0 ) {
01646 __TBB_store_with_release(op->status, FAILED);
01647 }
01648 else {
01649 if (mark<this->my_tail &&
01650 compare(this->my_array[0].first,
01651 this->my_array[this->my_tail-1].first)) {
01652
01653
01654 *(op->elem) = this->my_array[this->my_tail-1].first;
01655 --(this->my_tail);
01656 __TBB_store_with_release(op->status, SUCCEEDED);
01657 }
01658 else {
01659 *(op->elem) = this->my_array[0].first;
01660 if (mark == this->my_tail) --mark;
01661 --(this->my_tail);
01662 __TBB_store_with_release(op->status, SUCCEEDED);
01663 this->my_array[0].first=this->my_array[this->my_tail].first;
01664 if (this->my_tail > 1)
01665 reheap();
01666 }
01667 }
01668 }
01669 void internal_reserve(prio_operation *op) {
01670 if (this->my_reserved == true || this->my_tail == 0) {
01671 __TBB_store_with_release(op->status, FAILED);
01672 }
01673 else {
01674 this->my_reserved = true;
01675 *(op->elem) = reserved_item = this->my_array[0].first;
01676 if (mark == this->my_tail) --mark;
01677 --(this->my_tail);
01678 __TBB_store_with_release(op->status, SUCCEEDED);
01679 this->my_array[0].first = this->my_array[this->my_tail].first;
01680 if (this->my_tail > 1)
01681 reheap();
01682 }
01683 }
01684 void internal_consume(prio_operation *op) {
01685 this->my_reserved = false;
01686 __TBB_store_with_release(op->status, SUCCEEDED);
01687 }
01688 void internal_release(prio_operation *op) {
01689 if (this->my_tail >= this->my_array_size)
01690 this->grow_my_array( this->my_tail + 1 );
01691 this->my_array[this->my_tail] = std::make_pair(reserved_item, true);
01692 ++(this->my_tail);
01693 this->my_reserved = false;
01694 __TBB_store_with_release(op->status, SUCCEEDED);
01695 heapify();
01696 }
01697 private:
01698 Compare compare;
01699 size_type mark;
01700 input_type reserved_item;
01701
01702 void heapify() {
01703 if (!mark) mark = 1;
01704 for (; mark<this->my_tail; ++mark) {
01705 size_type cur_pos = mark;
01706 input_type to_place = this->my_array[mark].first;
01707 do {
01708 size_type parent = (cur_pos-1)>>1;
01709 if (!compare(this->my_array[parent].first, to_place))
01710 break;
01711 this->my_array[cur_pos].first = this->my_array[parent].first;
01712 cur_pos = parent;
01713 } while( cur_pos );
01714 this->my_array[cur_pos].first = to_place;
01715 }
01716 }
01717
01718 void reheap() {
01719 size_type cur_pos=0, child=1;
01720 while (child < mark) {
01721 size_type target = child;
01722 if (child+1<mark &&
01723 compare(this->my_array[child].first,
01724 this->my_array[child+1].first))
01725 ++target;
01726
01727 if (compare(this->my_array[target].first,
01728 this->my_array[this->my_tail].first))
01729 break;
01730 this->my_array[cur_pos].first = this->my_array[target].first;
01731 cur_pos = target;
01732 child = (cur_pos<<1)+1;
01733 }
01734 this->my_array[cur_pos].first = this->my_array[this->my_tail].first;
01735 }
01736 };
01737
01739
01742 template< typename T >
01743 class limiter_node : public graph_node, public receiver< T >, public sender< T > {
01744 protected:
01745 using graph_node::my_graph;
01746 public:
01747 typedef T input_type;
01748 typedef T output_type;
01749 typedef sender< input_type > predecessor_type;
01750 typedef receiver< output_type > successor_type;
01751
01752 private:
01753 task *my_root_task;
01754 size_t my_threshold;
01755 size_t my_count;
01756 internal::predecessor_cache< T > my_predecessors;
01757 spin_mutex my_mutex;
01758 internal::broadcast_cache< T > my_successors;
01759 int init_decrement_predecessors;
01760
01761 friend class internal::forward_task_bypass< limiter_node<T> >;
01762
01763
01764 friend class internal::decrementer< limiter_node<T> >;
01765
01766
01767 task * decrement_counter() {
01768 input_type v;
01769 task *rval = NULL;
01770
01771
01772 if ( my_predecessors.get_item( v ) == false
01773 || (rval = my_successors.try_put_task(v)) == NULL ) {
01774 spin_mutex::scoped_lock lock(my_mutex);
01775 --my_count;
01776 if ( !my_predecessors.empty() ) {
01777 task *rtask = new ( task::allocate_additional_child_of( *my_root_task ) )
01778 internal::forward_task_bypass< limiter_node<T> >( *this );
01779 __TBB_ASSERT(!rval, "Have two tasks to handle");
01780 return rtask;
01781 }
01782 }
01783 return rval;
01784 }
01785
01786 void forward() {
01787 {
01788 spin_mutex::scoped_lock lock(my_mutex);
01789 if ( my_count < my_threshold )
01790 ++my_count;
01791 else
01792 return;
01793 }
01794 task * rtask = decrement_counter();
01795 if(rtask) task::enqueue(*rtask);
01796 }
01797
01798 task *forward_task() {
01799 spin_mutex::scoped_lock lock(my_mutex);
01800 if ( my_count >= my_threshold )
01801 return NULL;
01802 ++my_count;
01803 task * rtask = decrement_counter();
01804 return rtask;
01805 }
01806
01807 public:
01809 internal::decrementer< limiter_node<T> > decrement;
01810
01812 limiter_node(graph &g, size_t threshold, int num_decrement_predecessors=0) :
01813 graph_node(g), my_root_task(g.root_task()), my_threshold(threshold), my_count(0),
01814 init_decrement_predecessors(num_decrement_predecessors),
01815 decrement(num_decrement_predecessors)
01816 {
01817 my_predecessors.set_owner(this);
01818 my_successors.set_owner(this);
01819 decrement.set_owner(this);
01820 }
01821
01823 limiter_node( const limiter_node& src ) :
01824 graph_node(src.my_graph), receiver<T>(), sender<T>(),
01825 my_root_task(src.my_root_task), my_threshold(src.my_threshold), my_count(0),
01826 init_decrement_predecessors(src.init_decrement_predecessors),
01827 decrement(src.init_decrement_predecessors)
01828 {
01829 my_predecessors.set_owner(this);
01830 my_successors.set_owner(this);
01831 decrement.set_owner(this);
01832 }
01833
01835 bool register_successor( receiver<output_type> &r ) {
01836 my_successors.register_successor(r);
01837 return true;
01838 }
01839
01841
01842 bool remove_successor( receiver<output_type> &r ) {
01843 r.remove_predecessor(*this);
01844 my_successors.remove_successor(r);
01845 return true;
01846 }
01847
01849 bool register_predecessor( predecessor_type &src ) {
01850 spin_mutex::scoped_lock lock(my_mutex);
01851 my_predecessors.add( src );
01852 if ( my_count < my_threshold && !my_successors.empty() ) {
01853 task::enqueue( * new ( task::allocate_additional_child_of( *my_root_task ) )
01854 internal::
01855 forward_task_bypass
01856 < limiter_node<T> >( *this ) );
01857 }
01858 return true;
01859 }
01860
01862 bool remove_predecessor( predecessor_type &src ) {
01863 my_predecessors.remove( src );
01864 return true;
01865 }
01866
01867 protected:
01868
01869 template< typename R, typename B > friend class run_and_put_task;
01870 template<typename X, typename Y> friend class internal::broadcast_cache;
01871 template<typename X, typename Y> friend class internal::round_robin_cache;
01873 task *try_put_task( const T &t ) {
01874 {
01875 spin_mutex::scoped_lock lock(my_mutex);
01876 if ( my_count >= my_threshold )
01877 return NULL;
01878 else
01879 ++my_count;
01880 }
01881
01882 task * rtask = my_successors.try_put_task(t);
01883
01884 if ( !rtask ) {
01885 spin_mutex::scoped_lock lock(my_mutex);
01886 --my_count;
01887 if ( !my_predecessors.empty() ) {
01888 rtask = new ( task::allocate_additional_child_of( *my_root_task ) )
01889 internal::forward_task_bypass< limiter_node<T> >( *this );
01890 }
01891 }
01892 return rtask;
01893 }
01894
01895 void reset() {
01896 my_count = 0;
01897 my_predecessors.reset();
01898 decrement.reset_receiver();
01899 }
01900
01901 void reset_receiver() { my_predecessors.reset(); }
01902 };
01903
01904 #include "internal/_flow_graph_join_impl.h"
01905
01906 using internal::reserving_port;
01907 using internal::queueing_port;
01908 using internal::tag_matching_port;
01909 using internal::input_port;
01910 using internal::tag_value;
01911 using internal::NO_TAG;
01912
01913 template<typename OutputTuple, graph_buffer_policy JP=queueing> class join_node;
01914
01915 template<typename OutputTuple>
01916 class join_node<OutputTuple,reserving>: public internal::unfolded_join_node<tbb::flow::tuple_size<OutputTuple>::value, reserving_port, OutputTuple, reserving> {
01917 private:
01918 static const int N = tbb::flow::tuple_size<OutputTuple>::value;
01919 typedef typename internal::unfolded_join_node<N, reserving_port, OutputTuple, reserving> unfolded_type;
01920 public:
01921 typedef OutputTuple output_type;
01922 typedef typename unfolded_type::input_ports_type input_ports_type;
01923 join_node(graph &g) : unfolded_type(g) { }
01924 join_node(const join_node &other) : unfolded_type(other) {}
01925 };
01926
01927 template<typename OutputTuple>
01928 class join_node<OutputTuple,queueing>: public internal::unfolded_join_node<tbb::flow::tuple_size<OutputTuple>::value, queueing_port, OutputTuple, queueing> {
01929 private:
01930 static const int N = tbb::flow::tuple_size<OutputTuple>::value;
01931 typedef typename internal::unfolded_join_node<N, queueing_port, OutputTuple, queueing> unfolded_type;
01932 public:
01933 typedef OutputTuple output_type;
01934 typedef typename unfolded_type::input_ports_type input_ports_type;
01935 join_node(graph &g) : unfolded_type(g) { }
01936 join_node(const join_node &other) : unfolded_type(other) {}
01937 };
01938
01939
01940 template<typename OutputTuple>
01941 class join_node<OutputTuple, tag_matching> : public internal::unfolded_join_node<tbb::flow::tuple_size<OutputTuple>::value,
01942 tag_matching_port, OutputTuple, tag_matching> {
01943 private:
01944 static const int N = tbb::flow::tuple_size<OutputTuple>::value;
01945 typedef typename internal::unfolded_join_node<N, tag_matching_port, OutputTuple, tag_matching> unfolded_type;
01946 public:
01947 typedef OutputTuple output_type;
01948 typedef typename unfolded_type::input_ports_type input_ports_type;
01949 template<typename B0, typename B1>
01950 join_node(graph &g, B0 b0, B1 b1) : unfolded_type(g, b0, b1) { }
01951 template<typename B0, typename B1, typename B2>
01952 join_node(graph &g, B0 b0, B1 b1, B2 b2) : unfolded_type(g, b0, b1, b2) { }
01953 template<typename B0, typename B1, typename B2, typename B3>
01954 join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3) : unfolded_type(g, b0, b1, b2, b3) { }
01955 template<typename B0, typename B1, typename B2, typename B3, typename B4>
01956 join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) : unfolded_type(g, b0, b1, b2, b3, b4) { }
01957 #if __TBB_VARIADIC_MAX >= 6
01958 template<typename B0, typename B1, typename B2, typename B3, typename B4, typename B5>
01959 join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4, B5 b5) : unfolded_type(g, b0, b1, b2, b3, b4, b5) { }
01960 #endif
01961 #if __TBB_VARIADIC_MAX >= 7
01962 template<typename B0, typename B1, typename B2, typename B3, typename B4, typename B5, typename B6>
01963 join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4, B5 b5, B6 b6) : unfolded_type(g, b0, b1, b2, b3, b4, b5, b6) { }
01964 #endif
01965 #if __TBB_VARIADIC_MAX >= 8
01966 template<typename B0, typename B1, typename B2, typename B3, typename B4, typename B5, typename B6, typename B7>
01967 join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4, B5 b5, B6 b6, B7 b7) : unfolded_type(g, b0, b1, b2, b3, b4, b5, b6, b7) { }
01968 #endif
01969 #if __TBB_VARIADIC_MAX >= 9
01970 template<typename B0, typename B1, typename B2, typename B3, typename B4, typename B5, typename B6, typename B7, typename B8>
01971 join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4, B5 b5, B6 b6, B7 b7, B8 b8) : unfolded_type(g, b0, b1, b2, b3, b4, b5, b6, b7, b8) { }
01972 #endif
01973 #if __TBB_VARIADIC_MAX >= 10
01974 template<typename B0, typename B1, typename B2, typename B3, typename B4, typename B5, typename B6, typename B7, typename B8, typename B9>
01975 join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4, B5 b5, B6 b6, B7 b7, B8 b8, B9 b9) : unfolded_type(g, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9) { }
01976 #endif
01977 join_node(const join_node &other) : unfolded_type(other) {}
01978 };
01979
01980 #if TBB_PREVIEW_GRAPH_NODES
01981
01982 #include "internal/_flow_graph_or_impl.h"
01983
01984 template<typename InputTuple>
01985 class or_node : public internal::unfolded_or_node<InputTuple> {
01986 private:
01987 static const int N = tbb::flow::tuple_size<InputTuple>::value;
01988 public:
01989 typedef typename internal::or_output_type<InputTuple>::type output_type;
01990 typedef typename internal::unfolded_or_node<InputTuple> unfolded_type;
01991 or_node(graph& g) : unfolded_type(g) { }
01992
01993 or_node( const or_node& other ) : unfolded_type(other) { }
01994 };
01995 #endif // TBB_PREVIEW_GRAPH_NODES
01996
01998 template< typename T >
01999 inline void make_edge( sender<T> &p, receiver<T> &s ) {
02000 p.register_successor( s );
02001 }
02002
02004 template< typename T >
02005 inline void remove_edge( sender<T> &p, receiver<T> &s ) {
02006 p.remove_successor( s );
02007 }
02008
02010 template< typename Body, typename Node >
02011 Body copy_body( Node &n ) {
02012 return n.template copy_function_object<Body>();
02013 }
02014
02015 }
02016
02017 using interface6::graph;
02018 using interface6::graph_node;
02019 using interface6::continue_msg;
02020 using interface6::sender;
02021 using interface6::receiver;
02022 using interface6::continue_receiver;
02023
02024 using interface6::source_node;
02025 using interface6::function_node;
02026 using interface6::multifunction_node;
02027 using interface6::split_node;
02028 using interface6::internal::output_port;
02029 #if TBB_PREVIEW_GRAPH_NODES
02030 using interface6::or_node;
02031 #endif
02032 using interface6::continue_node;
02033 using interface6::overwrite_node;
02034 using interface6::write_once_node;
02035 using interface6::broadcast_node;
02036 using interface6::buffer_node;
02037 using interface6::queue_node;
02038 using interface6::sequencer_node;
02039 using interface6::priority_queue_node;
02040 using interface6::limiter_node;
02041 using namespace interface6::internal::graph_policy_namespace;
02042 using interface6::join_node;
02043 using interface6::input_port;
02044 using interface6::copy_body;
02045 using interface6::make_edge;
02046 using interface6::remove_edge;
02047 using interface6::internal::NO_TAG;
02048 using interface6::internal::tag_value;
02049
02050 }
02051 }
02052
02053 #endif // __TBB_flow_graph_H