Intel(R) Threading Building Blocks Doxygen Documentation  version 4.2.3
flow_graph.h
Go to the documentation of this file.
1 /*
2  Copyright (c) 2005-2018 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 
18 
19 */
20 
21 #ifndef __TBB_flow_graph_H
22 #define __TBB_flow_graph_H
23 
24 #include "tbb_stddef.h"
25 #include "atomic.h"
26 #include "spin_mutex.h"
27 #include "null_mutex.h"
28 #include "spin_rw_mutex.h"
29 #include "null_rw_mutex.h"
30 #include "task.h"
32 #include "tbb_exception.h"
35 #include "tbb_profiling.h"
36 #include "task_arena.h"
37 
38 #if __TBB_PREVIEW_ASYNC_MSG
39 #include <vector> // std::vector in internal::async_storage
40 #include <memory> // std::shared_ptr in async_msg
41 #endif
42 
43 #if __TBB_PREVIEW_STREAMING_NODE
44 // For streaming_node
45 #include <array> // std::array
46 #include <unordered_map> // std::unordered_map
47 #include <type_traits> // std::decay, std::true_type, std::false_type
48 #endif // __TBB_PREVIEW_STREAMING_NODE
49 
50 #if TBB_DEPRECATED_FLOW_ENQUEUE
51 #define FLOW_SPAWN(a) tbb::task::enqueue((a))
52 #else
53 #define FLOW_SPAWN(a) tbb::task::spawn((a))
54 #endif
55 
56 // use the VC10 or gcc version of tuple if it is available.
57 #if __TBB_CPP11_TUPLE_PRESENT
58  #include <tuple>
59 namespace tbb {
60  namespace flow {
61  using std::tuple;
62  using std::tuple_size;
63  using std::tuple_element;
64  using std::get;
65  }
66 }
67 #else
68  #include "compat/tuple"
69 #endif
70 
71 #include<list>
72 #include<queue>
73 
84 namespace tbb {
85 namespace flow {
86 
88 enum concurrency { unlimited = 0, serial = 1 };
89 
90 namespace interface10 {
91 
93 struct null_type {};
94 
96 class continue_msg {};
97 
99 template< typename T > class sender;
100 template< typename T > class receiver;
102 template< typename T > class limiter_node; // needed for resetting decrementer
103 template< typename R, typename B > class run_and_put_task;
105 namespace internal {
107 template<typename T, typename M> class successor_cache;
108 template<typename T, typename M> class broadcast_cache;
109 template<typename T, typename M> class round_robin_cache;
110 template<typename T, typename M> class predecessor_cache;
111 template<typename T, typename M> class reservable_predecessor_cache;
113 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
114 // Holder of edges both for caches and for those nodes which do not have predecessor caches.
115 // C == receiver< ... > or sender< ... >, depending.
116 template<typename C>
117 class edge_container {
119 public:
120  typedef std::list<C *, tbb::tbb_allocator<C *> > edge_list_type;
122  void add_edge(C &s) {
123  built_edges.push_back(&s);
124  }
126  void delete_edge(C &s) {
127  for (typename edge_list_type::iterator i = built_edges.begin(); i != built_edges.end(); ++i) {
128  if (*i == &s) {
129  (void)built_edges.erase(i);
130  return; // only remove one predecessor per request
131  }
132  }
133  }
135  void copy_edges(edge_list_type &v) {
136  v = built_edges;
137  }
139  size_t edge_count() {
140  return (size_t)(built_edges.size());
141  }
143  void clear() {
144  built_edges.clear();
145  }
147  // methods remove the statement from all predecessors/successors liste in the edge
148  // container.
149  template< typename S > void sender_extract(S &s);
150  template< typename R > void receiver_extract(R &r);
152 private:
153  edge_list_type built_edges;
154 }; // class edge_container
155 #endif /* TBB_DEPRECATED_FLOW_NODE_EXTRACTION */
156 
157 } // namespace internal
159 } // namespace interface10
160 } // namespace flow
161 } // namespace tbb
162 
165 
166 namespace tbb {
167 namespace flow {
168 namespace interface10 {
169 
170 // enqueue left task if necessary. Returns the non-enqueued task if there is one.
171 static inline tbb::task *combine_tasks(graph& g, tbb::task * left, tbb::task * right) {
172  // if no RHS task, don't change left.
173  if (right == NULL) return left;
174  // right != NULL
175  if (left == NULL) return right;
176  if (left == SUCCESSFULLY_ENQUEUED) return right;
177  // left contains a task
178  if (right != SUCCESSFULLY_ENQUEUED) {
179  // both are valid tasks
181  return right;
182  }
183  return left;
184 }
186 #if __TBB_PREVIEW_ASYNC_MSG
188 template < typename T > class async_msg;
189 
190 namespace internal {
192 template < typename T > class async_storage;
194 template< typename T, typename = void >
197  typedef T filtered_type;
199  static const bool is_async_type = false;
201  static const void* to_void_ptr(const T& t) {
202  return static_cast<const void*>(&t);
203  }
205  static void* to_void_ptr(T& t) {
206  return static_cast<void*>(&t);
207  }
209  static const T& from_void_ptr(const void* p) {
210  return *static_cast<const T*>(p);
211  }
213  static T& from_void_ptr(void* p) {
214  return *static_cast<T*>(p);
215  }
217  static task* try_put_task_wrapper_impl(receiver<T>* const this_recv, const void *p, bool is_async) {
218  if (is_async) {
219  // This (T) is NOT async and incoming 'A<X> t' IS async
220  // Get data from async_msg
222  task* const new_task = msg.my_storage->subscribe(*this_recv, this_recv->graph_reference());
223  // finalize() must be called after subscribe() because set() can be called in finalize()
224  // and 'this_recv' client must be subscribed by this moment
225  msg.finalize();
226  return new_task;
227  }
228  else {
229  // Incoming 't' is NOT async
230  return this_recv->try_put_task(from_void_ptr(p));
231  }
232  }
233 };
235 template< typename T >
236 struct async_helpers< T, typename std::enable_if< std::is_base_of<async_msg<typename T::async_msg_data_type>, T>::value >::type > {
237  typedef T async_type;
238  typedef typename T::async_msg_data_type filtered_type;
240  static const bool is_async_type = true;
242  // Receiver-classes use const interfaces
243  static const void* to_void_ptr(const T& t) {
244  return static_cast<const void*>(&static_cast<const async_msg<filtered_type>&>(t));
245  }
247  static void* to_void_ptr(T& t) {
248  return static_cast<void*>(&static_cast<async_msg<filtered_type>&>(t));
249  }
251  // Sender-classes use non-const interfaces
252  static const T& from_void_ptr(const void* p) {
253  return *static_cast<const T*>(static_cast<const async_msg<filtered_type>*>(p));
254  }
256  static T& from_void_ptr(void* p) {
257  return *static_cast<T*>(static_cast<async_msg<filtered_type>*>(p));
258  }
260  // Used in receiver<T> class
261  static task* try_put_task_wrapper_impl(receiver<T>* const this_recv, const void *p, bool is_async) {
262  if (is_async) {
263  // Both are async
264  return this_recv->try_put_task(from_void_ptr(p));
265  }
266  else {
267  // This (T) is async and incoming 'X t' is NOT async
268  // Create async_msg for X
270  const T msg(t);
271  return this_recv->try_put_task(msg);
272  }
273  }
274 };
279  template< typename, typename > friend class internal::predecessor_cache;
280  template< typename, typename > friend class internal::reservable_predecessor_cache;
281 public:
285  virtual ~untyped_sender() {}
287  // NOTE: Following part of PUBLIC section is copy-paste from original sender<T> class
289  // TODO: Prevent untyped successor registration
290 
292  virtual bool register_successor( successor_type &r ) = 0;
295  virtual bool remove_successor( successor_type &r ) = 0;
298  virtual bool try_release( ) { return false; }
301  virtual bool try_consume( ) { return false; }
303 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
304  typedef internal::edge_container<successor_type> built_successors_type;
306  typedef built_successors_type::edge_list_type successor_list_type;
307  virtual built_successors_type &built_successors() = 0;
308  virtual void internal_add_built_successor( successor_type & ) = 0;
309  virtual void internal_delete_built_successor( successor_type & ) = 0;
310  virtual void copy_successors( successor_list_type &) = 0;
311  virtual size_t successor_count() = 0;
312 #endif /* TBB_DEPRECATED_FLOW_NODE_EXTRACTION */
313 protected:
315  template< typename X >
316  bool try_get( X &t ) {
318  }
321  template< typename X >
322  bool try_reserve( X &t ) {
324  }
326  virtual bool try_get_wrapper( void* p, bool is_async ) = 0;
327  virtual bool try_reserve_wrapper( void* p, bool is_async ) = 0;
328 };
331  template< typename, typename > friend class run_and_put_task;
332  template< typename > friend class limiter_node;
334  template< typename, typename > friend class internal::broadcast_cache;
335  template< typename, typename > friend class internal::round_robin_cache;
336  template< typename, typename > friend class internal::successor_cache;
338 #if __TBB_PREVIEW_OPENCL_NODE
339  template< typename, typename > friend class proxy_dependency_receiver;
340 #endif /* __TBB_PREVIEW_OPENCL_NODE */
341 public:
346  virtual ~untyped_receiver() {}
349  template<typename X>
350  bool try_put(const X& t) {
351  task *res = try_put_task(t);
352  if (!res) return false;
354  return true;
355  }
357  // NOTE: Following part of PUBLIC section is copy-paste from original receiver<T> class
359  // TODO: Prevent untyped predecessor registration
360 
362  virtual bool register_predecessor( predecessor_type & ) { return false; }
365  virtual bool remove_predecessor( predecessor_type & ) { return false; }
367 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
368  typedef internal::edge_container<predecessor_type> built_predecessors_type;
369  typedef built_predecessors_type::edge_list_type predecessor_list_type;
370  virtual built_predecessors_type &built_predecessors() = 0;
371  virtual void internal_add_built_predecessor( predecessor_type & ) = 0;
372  virtual void internal_delete_built_predecessor( predecessor_type & ) = 0;
373  virtual void copy_predecessors( predecessor_list_type & ) = 0;
374  virtual size_t predecessor_count() = 0;
375 #endif /* TBB_DEPRECATED_FLOW_NODE_EXTRACTION */
376 protected:
377  template<typename X>
378  task *try_put_task(const X& t) {
380  }
382  virtual task* try_put_task_wrapper( const void* p, bool is_async ) = 0;
384  virtual graph& graph_reference() = 0;
386  // NOTE: Following part of PROTECTED and PRIVATE sections is copy-paste from original receiver<T> class
391  virtual bool is_continue_receiver() { return false; }
392 };
393 
394 } // namespace internal
397 template< typename T >
399 public:
401  typedef T output_type;
406  virtual bool try_get( T & ) { return false; }
409  virtual bool try_reserve( T & ) { return false; }
411 protected:
412  virtual bool try_get_wrapper( void* p, bool is_async ) __TBB_override {
413  // Both async OR both are NOT async
416  }
417  // Else: this (T) is async OR incoming 't' is async
418  __TBB_ASSERT(false, "async_msg interface does not support 'pull' protocol in try_get()");
419  return false;
420  }
422  virtual bool try_reserve_wrapper( void* p, bool is_async ) __TBB_override {
423  // Both async OR both are NOT async
426  }
427  // Else: this (T) is async OR incoming 't' is async
428  __TBB_ASSERT(false, "async_msg interface does not support 'pull' protocol in try_reserve()");
429  return false;
430  }
431 }; // class sender<T>
434 template< typename T >
436  template< typename > friend class internal::async_storage;
437  template< typename, typename > friend struct internal::async_helpers;
438 public:
440  typedef T input_type;
441 
447  }
451  }
453 protected:
454  virtual task* try_put_task_wrapper( const void *p, bool is_async ) __TBB_override {
456  }
457 
459  virtual task *try_put_task(const T& t) = 0;
461 }; // class receiver<T>
463 #else // __TBB_PREVIEW_ASYNC_MSG
466 template< typename T >
467 class sender {
468 public:
470  typedef T output_type;
475  virtual ~sender() {}
477  // NOTE: Following part of PUBLIC section is partly copy-pasted in sender<T> under #if __TBB_PREVIEW_ASYNC_MSG
480  virtual bool register_successor( successor_type &r ) = 0;
483  virtual bool remove_successor( successor_type &r ) = 0;
486  virtual bool try_get( T & ) { return false; }
487 
489  virtual bool try_reserve( T & ) { return false; }
490 
492  virtual bool try_release( ) { return false; }
495  virtual bool try_consume( ) { return false; }
496 
497 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
498  typedef typename internal::edge_container<successor_type> built_successors_type;
500  typedef typename built_successors_type::edge_list_type successor_list_type;
501  virtual built_successors_type &built_successors() = 0;
502  virtual void internal_add_built_successor( successor_type & ) = 0;
503  virtual void internal_delete_built_successor( successor_type & ) = 0;
504  virtual void copy_successors( successor_list_type &) = 0;
505  virtual size_t successor_count() = 0;
506 #endif /* TBB_DEPRECATED_FLOW_NODE_EXTRACTION */
507 }; // class sender<T>
508 
510 template< typename T >
511 class receiver {
512 public:
514  typedef T input_type;
517  typedef sender<T> predecessor_type;
520  virtual ~receiver() {}
521 
523  bool try_put( const T& t ) {
524  task *res = try_put_task(t);
525  if (!res) return false;
527  return true;
528  }
529 
531 protected:
532  template< typename R, typename B > friend class run_and_put_task;
533  template< typename X, typename Y > friend class internal::broadcast_cache;
534  template< typename X, typename Y > friend class internal::round_robin_cache;
535  virtual task *try_put_task(const T& t) = 0;
536  virtual graph& graph_reference() = 0;
537 public:
538  // NOTE: Following part of PUBLIC and PROTECTED sections is copy-pasted in receiver<T> under #if __TBB_PREVIEW_ASYNC_MSG
541  virtual bool register_predecessor( predecessor_type & ) { return false; }
544  virtual bool remove_predecessor( predecessor_type & ) { return false; }
545 
546 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
547  typedef typename internal::edge_container<predecessor_type> built_predecessors_type;
548  typedef typename built_predecessors_type::edge_list_type predecessor_list_type;
549  virtual built_predecessors_type &built_predecessors() = 0;
550  virtual void internal_add_built_predecessor( predecessor_type & ) = 0;
551  virtual void internal_delete_built_predecessor( predecessor_type & ) = 0;
552  virtual void copy_predecessors( predecessor_list_type & ) = 0;
553  virtual size_t predecessor_count() = 0;
554 #endif /* TBB_DEPRECATED_FLOW_NODE_EXTRACTION */
556 protected:
558  template<typename U> friend class limiter_node;
560 
561  template<typename TT, typename M> friend class internal::successor_cache;
562  virtual bool is_continue_receiver() { return false; }
564 #if __TBB_PREVIEW_OPENCL_NODE
565  template< typename, typename > friend class proxy_dependency_receiver;
566 #endif /* __TBB_PREVIEW_OPENCL_NODE */
567 }; // class receiver<T>
569 #endif // __TBB_PREVIEW_ASYNC_MSG
572 
573 class continue_receiver : public receiver< continue_msg > {
574 public:
578 
581 
583  explicit continue_receiver( int number_of_predecessors = 0 ) {
586  }
587 
592  }
593 
598  return true;
599  }
600 
602 
608  return true;
609  }
610 
611 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
612  typedef internal::edge_container<predecessor_type> built_predecessors_type;
613  typedef built_predecessors_type::edge_list_type predecessor_list_type;
614  built_predecessors_type &built_predecessors() __TBB_override { return my_built_predecessors; }
615 
616  void internal_add_built_predecessor( predecessor_type &s) __TBB_override {
618  my_built_predecessors.add_edge( s );
619  }
621  void internal_delete_built_predecessor( predecessor_type &s) __TBB_override {
623  my_built_predecessors.delete_edge(s);
624  }
626  void copy_predecessors( predecessor_list_type &v) __TBB_override {
628  my_built_predecessors.copy_edges(v);
629  }
631  size_t predecessor_count() __TBB_override {
633  return my_built_predecessors.edge_count();
634  }
636 #endif /* TBB_DEPRECATED_FLOW_NODE_EXTRACTION */
638 protected:
639  template< typename R, typename B > friend class run_and_put_task;
640  template<typename X, typename Y> friend class internal::broadcast_cache;
641  template<typename X, typename Y> friend class internal::round_robin_cache;
642  // execute body is supposed to be too small to create a task for.
644  {
648  else
650  }
651  task * res = execute();
652  return res? res : SUCCESSFULLY_ENQUEUED;
653  }
654 
655 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
656  // continue_receiver must contain its own built_predecessors because it does
657  // not have a node_cache.
658  built_predecessors_type my_built_predecessors;
659 #endif
664  // the friend declaration in the base class did not eliminate the "protected class"
665  // error in gcc 4.1.2
666  template<typename U> friend class limiter_node;
670  if (f & rf_clear_edges) {
671 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
672  my_built_predecessors.clear();
673 #endif
675  }
676  }
679 
681  virtual task * execute() = 0;
682  template<typename TT, typename M> friend class internal::successor_cache;
683  bool is_continue_receiver() __TBB_override { return true; }
685 }; // class continue_receiver
687 } // interfaceX
689 #if __TBB_PREVIEW_MESSAGE_BASED_KEY_MATCHING
690  template <typename K, typename T>
691  K key_from_message( const T &t ) {
692  return t.key();
693  }
694 #endif /* __TBB_PREVIEW_MESSAGE_BASED_KEY_MATCHING */
697  using interface10::receiver;
699 } // flow
700 } // tbb
705 namespace tbb {
706 namespace flow {
707 namespace interface10 {
712 #if __TBB_PREVIEW_ASYNC_MSG
714 #endif
715 using namespace internal::graph_policy_namespace;
716 
717 template <typename C, typename N>
718 graph_iterator<C,N>::graph_iterator(C *g, bool begin) : my_graph(g), current_node(NULL)
719 {
720  if (begin) current_node = my_graph->my_nodes;
721  //else it is an end iterator by default
722 }
723 
724 template <typename C, typename N>
726  __TBB_ASSERT(current_node, "graph_iterator at end");
727  return *operator->();
728 }
730 template <typename C, typename N>
732  return current_node;
733 }
734 
735 template <typename C, typename N>
737  if (current_node) current_node = current_node->next;
738 }
741 inline graph::graph() : my_nodes(NULL), my_nodes_last(NULL), my_task_arena(NULL) {
743  own_context = true;
744  cancelled = false;
745  caught_exception = false;
746  my_context = new task_group_context(tbb::internal::FLOW_TASKS);
750  my_is_active = true;
751 }
752 
753 inline graph::graph(task_group_context& use_this_context) :
754  my_context(&use_this_context), my_nodes(NULL), my_nodes_last(NULL), my_task_arena(NULL) {
756  own_context = false;
760  my_is_active = true;
761 }
762 
763 inline graph::~graph() {
764  wait_for_all();
766  tbb::task::destroy(*my_root_task);
767  if (own_context) delete my_context;
768  delete my_task_arena;
769 }
771 inline void graph::reserve_wait() {
772  if (my_root_task) {
775  }
776 }
778 inline void graph::release_wait() {
782  }
783 }
784 
786  n->next = NULL;
787  {
790  if (my_nodes_last) my_nodes_last->next = n;
791  my_nodes_last = n;
792  if (!my_nodes) my_nodes = n;
793  }
794 }
797  {
799  __TBB_ASSERT(my_nodes && my_nodes_last, "graph::remove_node: Error: no registered nodes");
800  if (n->prev) n->prev->next = n->next;
801  if (n->next) n->next->prev = n->prev;
802  if (my_nodes_last == n) my_nodes_last = n->prev;
803  if (my_nodes == n) my_nodes = n->next;
804  }
805  n->prev = n->next = NULL;
806 }
807 
808 inline void graph::reset( reset_flags f ) {
809  // reset context
811 
812  if(my_context) my_context->reset();
813  cancelled = false;
814  caught_exception = false;
815  // reset all the nodes comprising the graph
816  for(iterator ii = begin(); ii != end(); ++ii) {
817  graph_node *my_p = &(*ii);
818  my_p->reset_node(f);
819  }
820  // Reattach the arena. Might be useful to run the graph in a particular task_arena
821  // while not limiting graph lifetime to a single task_arena::execute() call.
822  prepare_task_arena( /*reinit=*/true );
824  // now spawn the tasks necessary to start the graph
825  for(task_list_type::iterator rti = my_reset_task_list.begin(); rti != my_reset_task_list.end(); ++rti) {
827  }
828  my_reset_task_list.clear();
829 }
830 
831 inline graph::iterator graph::begin() { return iterator(this, true); }
833 inline graph::iterator graph::end() { return iterator(this, false); }
835 inline graph::const_iterator graph::begin() const { return const_iterator(this, true); }
837 inline graph::const_iterator graph::end() const { return const_iterator(this, false); }
839 inline graph::const_iterator graph::cbegin() const { return const_iterator(this, true); }
840 
841 inline graph::const_iterator graph::cend() const { return const_iterator(this, false); }
842 
843 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
844 inline void graph::set_name(const char *name) {
846 }
847 #endif
848 
849 inline graph_node::graph_node(graph& g) : my_graph(g) {
850  my_graph.register_node(this);
851 }
854  my_graph.remove_node(this);
855 }
856 
860 template < typename Output >
861 class source_node : public graph_node, public sender< Output > {
862 public:
864  typedef Output output_type;
865 
868 
869  //Source node has no input type
872 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
873  typedef typename sender<output_type>::built_successors_type built_successors_type;
874  typedef typename sender<output_type>::successor_list_type successor_list_type;
875 #endif
878  template< typename Body >
879  source_node( graph &g, Body body, bool is_active = true )
880  : graph_node(g), my_active(is_active), init_my_active(is_active),
881  my_body( new internal::source_body_leaf< output_type, Body>(body) ),
882  my_init_body( new internal::source_body_leaf< output_type, Body>(body) ),
883  my_reserved(false), my_has_cached_item(false)
884  {
885  my_successors.set_owner(this);
886  tbb::internal::fgt_node_with_body( tbb::internal::FLOW_SOURCE_NODE, &this->my_graph,
887  static_cast<sender<output_type> *>(this), this->my_body );
888  }
889 
891  source_node( const source_node& src ) :
892  graph_node(src.my_graph), sender<Output>(),
893  my_active(src.init_my_active),
894  init_my_active(src.init_my_active), my_body( src.my_init_body->clone() ), my_init_body(src.my_init_body->clone() ),
895  my_reserved(false), my_has_cached_item(false)
896  {
897  my_successors.set_owner(this);
898  tbb::internal::fgt_node_with_body( tbb::internal::FLOW_SOURCE_NODE, &this->my_graph,
899  static_cast<sender<output_type> *>(this), this->my_body );
900  }
901 
903  ~source_node() { delete my_body; delete my_init_body; }
904 
905 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
906  void set_name( const char *name ) __TBB_override {
908  }
909 #endif
913  spin_mutex::scoped_lock lock(my_mutex);
914  my_successors.register_successor(r);
915  if ( my_active )
916  spawn_put();
917  return true;
918  }
919 
922  spin_mutex::scoped_lock lock(my_mutex);
923  my_successors.remove_successor(r);
924  return true;
925  }
926 
927 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
928 
929  built_successors_type &built_successors() __TBB_override { return my_successors.built_successors(); }
931  void internal_add_built_successor( successor_type &r) __TBB_override {
932  spin_mutex::scoped_lock lock(my_mutex);
933  my_successors.internal_add_built_successor(r);
934  }
935 
936  void internal_delete_built_successor( successor_type &r) __TBB_override {
937  spin_mutex::scoped_lock lock(my_mutex);
938  my_successors.internal_delete_built_successor(r);
939  }
940 
941  size_t successor_count() __TBB_override {
943  return my_successors.successor_count();
944  }
945 
946  void copy_successors(successor_list_type &v) __TBB_override {
948  my_successors.copy_successors(v);
949  }
950 #endif /* TBB_DEPRECATED_FLOW_NODE_EXTRACTION */
951 
955  if ( my_reserved )
956  return false;
958  if ( my_has_cached_item ) {
959  v = my_cached_item;
960  my_has_cached_item = false;
961  return true;
962  }
963  // we've been asked to provide an item, but we have none. enqueue a task to
964  // provide one.
965  spawn_put();
966  return false;
967  }
968 
971  spin_mutex::scoped_lock lock(my_mutex);
972  if ( my_reserved ) {
973  return false;
974  }
975 
976  if ( my_has_cached_item ) {
977  v = my_cached_item;
978  my_reserved = true;
979  return true;
980  } else {
981  return false;
982  }
983  }
984 
986 
988  spin_mutex::scoped_lock lock(my_mutex);
989  __TBB_ASSERT( my_reserved && my_has_cached_item, "releasing non-existent reservation" );
990  my_reserved = false;
991  if(!my_successors.empty())
992  spawn_put();
993  return true;
994  }
995 
998  spin_mutex::scoped_lock lock(my_mutex);
999  __TBB_ASSERT( my_reserved && my_has_cached_item, "consuming non-existent reservation" );
1000  my_reserved = false;
1001  my_has_cached_item = false;
1002  if ( !my_successors.empty() ) {
1003  spawn_put();
1004  }
1005  return true;
1006  }
1007 
1009  void activate() {
1010  spin_mutex::scoped_lock lock(my_mutex);
1011  my_active = true;
1012  if (!my_successors.empty())
1013  spawn_put();
1014  }
1015 
1016  template<typename Body>
1018  internal::source_body<output_type> &body_ref = *this->my_body;
1019  return dynamic_cast< internal::source_body_leaf<output_type, Body> & >(body_ref).get_body();
1020  }
1021 
1022 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
1023  void extract( ) __TBB_override {
1024  my_successors.built_successors().sender_extract(*this); // removes "my_owner" == this from each successor
1025  my_active = init_my_active;
1026  my_reserved = false;
1027  if(my_has_cached_item) my_has_cached_item = false;
1028  }
1029 #endif
1030 
1031 protected:
1032 
1035  my_active = init_my_active;
1036  my_reserved =false;
1037  if(my_has_cached_item) {
1038  my_has_cached_item = false;
1039  }
1040  if(f & rf_clear_edges) my_successors.clear();
1041  if(f & rf_reset_bodies) {
1042  internal::source_body<output_type> *tmp = my_init_body->clone();
1043  delete my_body;
1044  my_body = tmp;
1045  }
1046  if(my_active)
1047  internal::add_task_to_graph_reset_list(this->my_graph, create_put_task());
1048  }
1050 private:
1061  // used by apply_body_bypass, can invoke body of node.
1064  if ( my_reserved ) {
1065  return false;
1066  }
1067  if ( !my_has_cached_item ) {
1068  tbb::internal::fgt_begin_body( my_body );
1069  bool r = (*my_body)(my_cached_item);
1071  if (r) {
1072  my_has_cached_item = true;
1073  }
1074  }
1075  if ( my_has_cached_item ) {
1076  v = my_cached_item;
1077  my_reserved = true;
1078  return true;
1079  } else {
1080  return false;
1081  }
1082  }
1084  // when resetting, and if the source_node was created with my_active == true, then
1085  // when we reset the node we must store a task to run the node, and spawn it only
1086  // after the reset is complete and is_active() is again true. This is why we don't
1087  // test for is_active() here.
1089  return ( new ( task::allocate_additional_child_of( *(this->my_graph.root_task()) ) )
1091  }
1092 
1094  void spawn_put( ) {
1095  if(internal::is_graph_active(this->my_graph)) {
1096  internal::spawn_in_graph_arena(this->my_graph, *create_put_task());
1097  }
1098  }
1099 
1103  output_type v;
1104  if ( !try_reserve_apply_body(v) )
1105  return NULL;
1106 
1107  task *last_task = my_successors.try_put_task(v);
1108  if ( last_task )
1109  try_consume();
1110  else
1111  try_release();
1112  return last_task;
1113  }
1114 }; // class source_node
1115 
1117 template < typename Input, typename Output = continue_msg, typename Policy = queueing, typename Allocator=cache_aligned_allocator<Input> >
1118 class function_node : public graph_node, public internal::function_input<Input,Output,Policy,Allocator>, public internal::function_output<Output> {
1119 public:
1120  typedef Input input_type;
1121  typedef Output output_type;
1127 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
1128  typedef typename input_impl_type::predecessor_list_type predecessor_list_type;
1129  typedef typename fOutput_type::successor_list_type successor_list_type;
1130 #endif
1131  using input_impl_type::my_predecessors;
1132 
1134  // input_queue_type is allocated here, but destroyed in the function_input_base.
1135  // TODO: pass the graph_buffer_policy to the function_input_base so it can all
1136  // be done in one place. This would be an interface-breaking change.
1137  template< typename Body >
1138  function_node( graph &g, size_t concurrency, Body body ) :
1139  graph_node(g), input_impl_type(g, concurrency, body) {
1140  tbb::internal::fgt_node_with_body( tbb::internal::FLOW_FUNCTION_NODE, &this->my_graph,
1141  static_cast<receiver<input_type> *>(this), static_cast<sender<output_type> *>(this), this->my_body );
1142  }
1143 
1146  graph_node(src.my_graph),
1147  input_impl_type(src),
1148  fOutput_type() {
1149  tbb::internal::fgt_node_with_body( tbb::internal::FLOW_FUNCTION_NODE, &this->my_graph,
1150  static_cast<receiver<input_type> *>(this), static_cast<sender<output_type> *>(this), this->my_body );
1151  }
1152 
1153 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
1154  void set_name( const char *name ) __TBB_override {
1156  }
1157 #endif
1158 
1159 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
1160  void extract( ) __TBB_override {
1161  my_predecessors.built_predecessors().receiver_extract(*this);
1162  successors().built_successors().sender_extract(*this);
1163  }
1164 #endif
1165 
1166 protected:
1167  template< typename R, typename B > friend class run_and_put_task;
1168  template<typename X, typename Y> friend class internal::broadcast_cache;
1169  template<typename X, typename Y> friend class internal::round_robin_cache;
1170  using input_impl_type::try_put_task;
1171 
1172  internal::broadcast_cache<output_type> &successors () __TBB_override { return fOutput_type::my_successors; }
1173 
1175  input_impl_type::reset_function_input(f);
1176  // TODO: use clear() instead.
1177  if(f & rf_clear_edges) {
1178  successors().clear();
1179  my_predecessors.clear();
1180  }
1181  __TBB_ASSERT(!(f & rf_clear_edges) || successors().empty(), "function_node successors not empty");
1182  __TBB_ASSERT(this->my_predecessors.empty(), "function_node predecessors not empty");
1183  }
1184 
1185 }; // class function_node
1186 
1188 // Output is a tuple of output types.
1189 template < typename Input, typename Output, typename Policy = queueing, typename Allocator=cache_aligned_allocator<Input> >
1191  public graph_node,
1193  <
1194  Input,
1195  typename internal::wrap_tuple_elements<
1196  tbb::flow::tuple_size<Output>::value, // #elements in tuple
1197  internal::multifunction_output, // wrap this around each element
1198  Output // the tuple providing the types
1199  >::type,
1200  Policy,
1201  Allocator
1202  > {
1203 protected:
1205 public:
1206  typedef Input input_type;
1211 private:
1213  using input_impl_type::my_predecessors;
1214 public:
1215  template<typename Body>
1216  multifunction_node( graph &g, size_t concurrency, Body body ) :
1217  graph_node(g), base_type(g,concurrency, body) {
1218  tbb::internal::fgt_multioutput_node_with_body<N>( tbb::internal::FLOW_MULTIFUNCTION_NODE,
1219  &this->my_graph, static_cast<receiver<input_type> *>(this),
1220  this->output_ports(), this->my_body );
1221  }
1222 
1224  graph_node(other.my_graph), base_type(other) {
1225  tbb::internal::fgt_multioutput_node_with_body<N>( tbb::internal::FLOW_MULTIFUNCTION_NODE,
1226  &this->my_graph, static_cast<receiver<input_type> *>(this),
1227  this->output_ports(), this->my_body );
1228  }
1229 
1230 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
1231  void set_name( const char *name ) __TBB_override {
1233  }
1234 #endif
1235 
1236 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
1237  void extract( ) __TBB_override {
1238  my_predecessors.built_predecessors().receiver_extract(*this);
1239  base_type::extract();
1240  }
1241 #endif
1242  // all the guts are in multifunction_input...
1243 protected:
1244  void reset_node(reset_flags f) __TBB_override { base_type::reset(f); }
1245 }; // multifunction_node
1246 
1248 // successors. The node has unlimited concurrency, so it does not reject inputs.
1249 template<typename TupleType, typename Allocator=cache_aligned_allocator<TupleType> >
1250 class split_node : public graph_node, public receiver<TupleType> {
1253 public:
1254  typedef TupleType input_type;
1255  typedef Allocator allocator_type;
1256 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
1258  typedef typename base_type::predecessor_list_type predecessor_list_type;
1260  typedef typename predecessor_cache_type::built_predecessors_type built_predecessors_type;
1261 #endif
1262 
1263  typedef typename internal::wrap_tuple_elements<
1264  N, // #elements in tuple
1265  internal::multifunction_output, // wrap this around each element
1266  TupleType // the tuple providing the types
1268 
1269  explicit split_node(graph &g) : graph_node(g)
1270  {
1271  tbb::internal::fgt_multioutput_node<N>(tbb::internal::FLOW_SPLIT_NODE, &this->my_graph,
1272  static_cast<receiver<input_type> *>(this), this->output_ports());
1273  }
1274  split_node( const split_node & other) : graph_node(other.my_graph), base_type(other)
1275  {
1276  tbb::internal::fgt_multioutput_node<N>(tbb::internal::FLOW_SPLIT_NODE, &this->my_graph,
1277  static_cast<receiver<input_type> *>(this), this->output_ports());
1278  }
1279 
1280 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
1281  void set_name( const char *name ) __TBB_override {
1283  }
1284 #endif
1285 
1286  output_ports_type &output_ports() { return my_output_ports; }
1287 
1288 protected:
1289  task *try_put_task(const TupleType& t) __TBB_override {
1290  // Sending split messages in parallel is not justified, as overheads would prevail.
1291  // Also, we do not have successors here. So we just tell the task returned here is successful.
1292  return internal::emit_element<N>::emit_this(this->my_graph, t, output_ports());
1293  }
1294  void reset_node(reset_flags f) __TBB_override {
1295  if (f & rf_clear_edges)
1298  __TBB_ASSERT(!(f & rf_clear_edges) || internal::clear_element<N>::this_empty(my_output_ports), "split_node reset failed");
1299  }
1302  return my_graph;
1303  }
1304 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
1305 private:
1306  void extract() __TBB_override {}
1307 
1309  void internal_add_built_predecessor(predecessor_type&) __TBB_override {}
1310 
1312  void internal_delete_built_predecessor(predecessor_type&) __TBB_override {}
1314  size_t predecessor_count() __TBB_override { return 0; }
1315 
1316  void copy_predecessors(predecessor_list_type&) __TBB_override {}
1317 
1318  built_predecessors_type &built_predecessors() __TBB_override { return my_predessors; }
1319 
1321  built_predecessors_type my_predessors;
1322 #endif /* TBB_DEPRECATED_FLOW_NODE_EXTRACTION */
1323 
1324 private:
1326 };
1327 
1329 template <typename Output, typename Policy = internal::Policy<void> >
1330 class continue_node : public graph_node, public internal::continue_input<Output, Policy>,
1331  public internal::function_output<Output> {
1332 public:
1334  typedef Output output_type;
1339 
1341  template <typename Body >
1342  continue_node( graph &g, Body body ) :
1343  graph_node(g), input_impl_type( g, body ) {
1344  tbb::internal::fgt_node_with_body( tbb::internal::FLOW_CONTINUE_NODE, &this->my_graph,
1345  static_cast<receiver<input_type> *>(this),
1346  static_cast<sender<output_type> *>(this), this->my_body );
1347  }
1348 
1349 
1351  template <typename Body >
1352  continue_node( graph &g, int number_of_predecessors, Body body ) :
1353  graph_node(g), input_impl_type( g, number_of_predecessors, body ) {
1354  tbb::internal::fgt_node_with_body( tbb::internal::FLOW_CONTINUE_NODE, &this->my_graph,
1355  static_cast<receiver<input_type> *>(this),
1356  static_cast<sender<output_type> *>(this), this->my_body );
1357  }
1358 
1361  graph_node(src.my_graph), input_impl_type(src),
1362  internal::function_output<Output>() {
1363  tbb::internal::fgt_node_with_body( tbb::internal::FLOW_CONTINUE_NODE, &this->my_graph,
1364  static_cast<receiver<input_type> *>(this),
1365  static_cast<sender<output_type> *>(this), this->my_body );
1366  }
1367 
1368 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
1369  void set_name( const char *name ) __TBB_override {
1371  }
1372 #endif
1373 
1374 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
1375  void extract() __TBB_override {
1376  input_impl_type::my_built_predecessors.receiver_extract(*this);
1377  successors().built_successors().sender_extract(*this);
1378  }
1379 #endif
1380 
1381 protected:
1382  template< typename R, typename B > friend class run_and_put_task;
1383  template<typename X, typename Y> friend class internal::broadcast_cache;
1384  template<typename X, typename Y> friend class internal::round_robin_cache;
1385  using input_impl_type::try_put_task;
1386  internal::broadcast_cache<output_type> &successors () __TBB_override { return fOutput_type::my_successors; }
1387 
1389  input_impl_type::reset_receiver(f);
1390  if(f & rf_clear_edges)successors().clear();
1391  __TBB_ASSERT(!(f & rf_clear_edges) || successors().empty(), "continue_node not reset");
1392  }
1393 }; // continue_node
1394 
1396 template <typename T>
1397 class broadcast_node : public graph_node, public receiver<T>, public sender<T> {
1398 public:
1399  typedef T input_type;
1400  typedef T output_type;
1403 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
1404  typedef typename receiver<input_type>::predecessor_list_type predecessor_list_type;
1405  typedef typename sender<output_type>::successor_list_type successor_list_type;
1406 #endif
1407 private:
1409 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
1410  internal::edge_container<predecessor_type> my_built_predecessors;
1411  spin_mutex pred_mutex; // serialize accesses on edge_container
1412 #endif
1413 public:
1414 
1415  explicit broadcast_node(graph& g) : graph_node(g) {
1416  my_successors.set_owner( this );
1417  tbb::internal::fgt_node( tbb::internal::FLOW_BROADCAST_NODE, &this->my_graph,
1418  static_cast<receiver<input_type> *>(this), static_cast<sender<output_type> *>(this) );
1419  }
1420 
1421  // Copy constructor
1423  graph_node(src.my_graph), receiver<T>(), sender<T>()
1424  {
1425  my_successors.set_owner( this );
1426  tbb::internal::fgt_node( tbb::internal::FLOW_BROADCAST_NODE, &this->my_graph,
1427  static_cast<receiver<input_type> *>(this), static_cast<sender<output_type> *>(this) );
1428  }
1430 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
1431  void set_name( const char *name ) __TBB_override {
1433  }
1434 #endif
1435 
1438  my_successors.register_successor( r );
1439  return true;
1440  }
1441 
1444  my_successors.remove_successor( r );
1445  return true;
1446  }
1447 
1448 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
1449  typedef typename sender<T>::built_successors_type built_successors_type;
1450 
1451  built_successors_type &built_successors() __TBB_override { return my_successors.built_successors(); }
1452 
1453  void internal_add_built_successor(successor_type &r) __TBB_override {
1454  my_successors.internal_add_built_successor(r);
1455  }
1456 
1457  void internal_delete_built_successor(successor_type &r) __TBB_override {
1458  my_successors.internal_delete_built_successor(r);
1459  }
1460 
1461  size_t successor_count() __TBB_override {
1462  return my_successors.successor_count();
1463  }
1464 
1465  void copy_successors(successor_list_type &v) __TBB_override {
1466  my_successors.copy_successors(v);
1467  }
1468 
1469  typedef typename receiver<T>::built_predecessors_type built_predecessors_type;
1471  built_predecessors_type &built_predecessors() __TBB_override { return my_built_predecessors; }
1472 
1473  void internal_add_built_predecessor( predecessor_type &p) __TBB_override {
1474  spin_mutex::scoped_lock l(pred_mutex);
1475  my_built_predecessors.add_edge(p);
1476  }
1477 
1478  void internal_delete_built_predecessor( predecessor_type &p) __TBB_override {
1480  my_built_predecessors.delete_edge(p);
1481  }
1482 
1483  size_t predecessor_count() __TBB_override {
1484  spin_mutex::scoped_lock l(pred_mutex);
1485  return my_built_predecessors.edge_count();
1486  }
1487 
1488  void copy_predecessors(predecessor_list_type &v) __TBB_override {
1490  my_built_predecessors.copy_edges(v);
1491  }
1492 
1493  void extract() __TBB_override {
1494  my_built_predecessors.receiver_extract(*this);
1495  my_successors.built_successors().sender_extract(*this);
1496  }
1497 #endif /* TBB_DEPRECATED_FLOW_NODE_EXTRACTION */
1498 
1499 protected:
1500  template< typename R, typename B > friend class run_and_put_task;
1501  template<typename X, typename Y> friend class internal::broadcast_cache;
1502  template<typename X, typename Y> friend class internal::round_robin_cache;
1505  task *new_task = my_successors.try_put_task(t);
1506  if (!new_task) new_task = SUCCESSFULLY_ENQUEUED;
1507  return new_task;
1508  }
1511  return my_graph;
1512  }
1513 
1515 
1516  void reset_node(reset_flags f) __TBB_override {
1518  my_successors.clear();
1519 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
1520  my_built_predecessors.clear();
1521 #endif
1522  }
1523  __TBB_ASSERT(!(f & rf_clear_edges) || my_successors.empty(), "Error resetting broadcast_node");
1524  }
1525 }; // broadcast_node
1526 
1528 template <typename T, typename A=cache_aligned_allocator<T> >
1529 class buffer_node : public graph_node, public internal::reservable_item_buffer<T, A>, public receiver<T>, public sender<T> {
1530 public:
1531  typedef T input_type;
1532  typedef T output_type;
1536 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
1537  typedef typename receiver<input_type>::predecessor_list_type predecessor_list_type;
1538  typedef typename sender<output_type>::successor_list_type successor_list_type;
1539 #endif
1540 protected:
1541  typedef size_t size_type;
1544 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
1545  internal::edge_container<predecessor_type> my_built_predecessors;
1546 #endif
1550  enum op_type {reg_succ, rem_succ, req_item, res_item, rel_res, con_res, put_item, try_fwd_task
1551 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
1552  , add_blt_succ, del_blt_succ,
1553  add_blt_pred, del_blt_pred,
1554  blt_succ_cnt, blt_pred_cnt,
1555  blt_succ_cpy, blt_pred_cpy // create vector copies of preds and succs
1556 #endif
1557  };
1558 
1559  // implements the aggregator_operation concept
1560  class buffer_operation : public internal::aggregated_operation< buffer_operation > {
1561  public:
1562  char type;
1563 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
1564  task * ltask;
1565  union {
1566  input_type *elem;
1567  successor_type *r;
1568  predecessor_type *p;
1569  size_t cnt_val;
1570  successor_list_type *svec;
1571  predecessor_list_type *pvec;
1572  };
1573 #else
1574  T *elem;
1577 #endif
1578  buffer_operation(const T& e, op_type t) : type(char(t))
1579 
1580 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
1581  , ltask(NULL), elem(const_cast<T*>(&e))
1582 #else
1583  , elem(const_cast<T*>(&e)) , ltask(NULL)
1584 #endif
1585  {}
1586  buffer_operation(op_type t) : type(char(t)), ltask(NULL) {}
1587  };
1588 
1590  typedef internal::aggregating_functor<class_type, buffer_operation> handler_type;
1591  friend class internal::aggregating_functor<class_type, buffer_operation>;
1592  internal::aggregator< handler_type, buffer_operation> my_aggregator;
1593 
1594  virtual void handle_operations(buffer_operation *op_list) {
1595  handle_operations_impl(op_list, this);
1596  }
1597 
1598  template<typename derived_type>
1599  void handle_operations_impl(buffer_operation *op_list, derived_type* derived) {
1600  __TBB_ASSERT(static_cast<class_type*>(derived) == this, "'this' is not a base class for derived");
1601 
1602  buffer_operation *tmp = NULL;
1603  bool try_forwarding = false;
1604  while (op_list) {
1605  tmp = op_list;
1606  op_list = op_list->next;
1607  switch (tmp->type) {
1608  case reg_succ: internal_reg_succ(tmp); try_forwarding = true; break;
1609  case rem_succ: internal_rem_succ(tmp); break;
1610  case req_item: internal_pop(tmp); break;
1611  case res_item: internal_reserve(tmp); break;
1612  case rel_res: internal_release(tmp); try_forwarding = true; break;
1613  case con_res: internal_consume(tmp); try_forwarding = true; break;
1614  case put_item: try_forwarding = internal_push(tmp); break;
1615  case try_fwd_task: internal_forward_task(tmp); break;
1616 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
1617  // edge recording
1618  case add_blt_succ: internal_add_built_succ(tmp); break;
1619  case del_blt_succ: internal_del_built_succ(tmp); break;
1620  case add_blt_pred: internal_add_built_pred(tmp); break;
1621  case del_blt_pred: internal_del_built_pred(tmp); break;
1622  case blt_succ_cnt: internal_succ_cnt(tmp); break;
1623  case blt_pred_cnt: internal_pred_cnt(tmp); break;
1624  case blt_succ_cpy: internal_copy_succs(tmp); break;
1625  case blt_pred_cpy: internal_copy_preds(tmp); break;
1626 #endif
1627  }
1628  }
1630  derived->order();
1631 
1632  if (try_forwarding && !forwarder_busy) {
1633  if(internal::is_graph_active(this->my_graph)) {
1634  forwarder_busy = true;
1635  task *new_task = new(task::allocate_additional_child_of(*(this->my_graph.root_task()))) internal::
1637  < buffer_node<input_type, A> >(*this);
1638  // tmp should point to the last item handled by the aggregator. This is the operation
1639  // the handling thread enqueued. So modifying that record will be okay.
1640  // workaround for icc bug
1641  tbb::task *z = tmp->ltask;
1642  graph &g = this->my_graph;
1643  tmp->ltask = combine_tasks(g, z, new_task); // in case the op generated a task
1644  }
1645  }
1646  } // handle_operations
1647 
1648  inline task *grab_forwarding_task( buffer_operation &op_data) {
1649  return op_data.ltask;
1650  }
1651 
1653  task *ft = grab_forwarding_task(op_data);
1654  if(ft) {
1655  internal::spawn_in_graph_arena(graph_reference(), *ft);
1656  return true;
1657  }
1658  return false;
1659  }
1662  virtual task *forward_task() {
1663  buffer_operation op_data(try_fwd_task);
1664  task *last_task = NULL;
1665  do {
1666  op_data.status = internal::WAIT;
1667  op_data.ltask = NULL;
1668  my_aggregator.execute(&op_data);
1670  // workaround for icc bug
1671  tbb::task *xtask = op_data.ltask;
1672  graph& g = this->my_graph;
1673  last_task = combine_tasks(g, last_task, xtask);
1674  } while (op_data.status ==internal::SUCCEEDED);
1675  return last_task;
1676  }
1677 
1680  my_successors.register_successor(*(op->r));
1682  }
1686  my_successors.remove_successor(*(op->r));
1688  }
1689 
1690 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
1691  typedef typename sender<T>::built_successors_type built_successors_type;
1692 
1693  built_successors_type &built_successors() __TBB_override { return my_successors.built_successors(); }
1694 
1695  virtual void internal_add_built_succ(buffer_operation *op) {
1696  my_successors.internal_add_built_successor(*(op->r));
1698  }
1699 
1700  virtual void internal_del_built_succ(buffer_operation *op) {
1701  my_successors.internal_delete_built_successor(*(op->r));
1703  }
1705  typedef typename receiver<T>::built_predecessors_type built_predecessors_type;
1706 
1707  built_predecessors_type &built_predecessors() __TBB_override { return my_built_predecessors; }
1709  virtual void internal_add_built_pred(buffer_operation *op) {
1710  my_built_predecessors.add_edge(*(op->p));
1712  }
1714  virtual void internal_del_built_pred(buffer_operation *op) {
1715  my_built_predecessors.delete_edge(*(op->p));
1717  }
1718 
1719  virtual void internal_succ_cnt(buffer_operation *op) {
1720  op->cnt_val = my_successors.successor_count();
1722  }
1723 
1724  virtual void internal_pred_cnt(buffer_operation *op) {
1725  op->cnt_val = my_built_predecessors.edge_count();
1727  }
1728 
1729  virtual void internal_copy_succs(buffer_operation *op) {
1730  my_successors.copy_successors(*(op->svec));
1732  }
1733 
1734  virtual void internal_copy_preds(buffer_operation *op) {
1735  my_built_predecessors.copy_edges(*(op->pvec));
1737  }
1738 
1739 #endif /* TBB_DEPRECATED_FLOW_NODE_EXTRACTION */
1740 
1741 private:
1742  void order() {}
1744  bool is_item_valid() {
1745  return this->my_item_valid(this->my_tail - 1);
1746  }
1747 
1748  void try_put_and_add_task(task*& last_task) {
1749  task *new_task = my_successors.try_put_task(this->back());
1750  if (new_task) {
1751  // workaround for icc bug
1752  graph& g = this->my_graph;
1753  last_task = combine_tasks(g, last_task, new_task);
1754  this->destroy_back();
1755  }
1756  }
1758 protected:
1760  virtual void internal_forward_task(buffer_operation *op) {
1761  internal_forward_task_impl(op, this);
1762  }
1764  template<typename derived_type>
1765  void internal_forward_task_impl(buffer_operation *op, derived_type* derived) {
1766  __TBB_ASSERT(static_cast<class_type*>(derived) == this, "'this' is not a base class for derived");
1768  if (this->my_reserved || !derived->is_item_valid()) {
1770  this->forwarder_busy = false;
1771  return;
1772  }
1773  // Try forwarding, giving each successor a chance
1774  task * last_task = NULL;
1775  size_type counter = my_successors.size();
1776  for (; counter > 0 && derived->is_item_valid(); --counter)
1777  derived->try_put_and_add_task(last_task);
1778 
1779  op->ltask = last_task; // return task
1780  if (last_task && !counter) {
1782  }
1783  else {
1785  forwarder_busy = false;
1786  }
1787  }
1788 
1789  virtual bool internal_push(buffer_operation *op) {
1790  this->push_back(*(op->elem));
1792  return true;
1793  }
1794 
1795  virtual void internal_pop(buffer_operation *op) {
1796  if(this->pop_back(*(op->elem))) {
1798  }
1799  else {
1801  }
1802  }
1803 
1805  if(this->reserve_front(*(op->elem))) {
1807  }
1808  else {
1810  }
1811  }
1813  virtual void internal_consume(buffer_operation *op) {
1814  this->consume_front();
1816  }
1819  this->release_front();
1821  }
1823 public:
1825  explicit buffer_node( graph &g ) : graph_node(g), internal::reservable_item_buffer<T>(),
1826  forwarder_busy(false) {
1827  my_successors.set_owner(this);
1828  my_aggregator.initialize_handler(handler_type(this));
1829  tbb::internal::fgt_node( tbb::internal::FLOW_BUFFER_NODE, &this->my_graph,
1830  static_cast<receiver<input_type> *>(this), static_cast<sender<output_type> *>(this) );
1831  }
1832 
1834  buffer_node( const buffer_node& src ) : graph_node(src.my_graph),
1835  internal::reservable_item_buffer<T>(), receiver<T>(), sender<T>() {
1836  forwarder_busy = false;
1837  my_successors.set_owner(this);
1838  my_aggregator.initialize_handler(handler_type(this));
1839  tbb::internal::fgt_node( tbb::internal::FLOW_BUFFER_NODE, &this->my_graph,
1840  static_cast<receiver<input_type> *>(this), static_cast<sender<output_type> *>(this) );
1841  }
1842 
1843 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
1844  void set_name( const char *name ) __TBB_override {
1846  }
1847 #endif
1848 
1849  //
1850  // message sender implementation
1851  //
1852 
1854 
1856  buffer_operation op_data(reg_succ);
1857  op_data.r = &r;
1858  my_aggregator.execute(&op_data);
1859  (void)enqueue_forwarding_task(op_data);
1860  return true;
1861  }
1862 
1863 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
1864  void internal_add_built_successor( successor_type &r) __TBB_override {
1865  buffer_operation op_data(add_blt_succ);
1866  op_data.r = &r;
1867  my_aggregator.execute(&op_data);
1868  }
1870  void internal_delete_built_successor( successor_type &r) __TBB_override {
1871  buffer_operation op_data(del_blt_succ);
1872  op_data.r = &r;
1873  my_aggregator.execute(&op_data);
1874  }
1876  void internal_add_built_predecessor( predecessor_type &p) __TBB_override {
1877  buffer_operation op_data(add_blt_pred);
1878  op_data.p = &p;
1879  my_aggregator.execute(&op_data);
1880  }
1882  void internal_delete_built_predecessor( predecessor_type &p) __TBB_override {
1883  buffer_operation op_data(del_blt_pred);
1884  op_data.p = &p;
1885  my_aggregator.execute(&op_data);
1886  }
1888  size_t predecessor_count() __TBB_override {
1889  buffer_operation op_data(blt_pred_cnt);
1890  my_aggregator.execute(&op_data);
1891  return op_data.cnt_val;
1892  }
1894  size_t successor_count() __TBB_override {
1895  buffer_operation op_data(blt_succ_cnt);
1896  my_aggregator.execute(&op_data);
1897  return op_data.cnt_val;
1898  }
1899 
1900  void copy_predecessors( predecessor_list_type &v ) __TBB_override {
1901  buffer_operation op_data(blt_pred_cpy);
1902  op_data.pvec = &v;
1903  my_aggregator.execute(&op_data);
1904  }
1905 
1906  void copy_successors( successor_list_type &v ) __TBB_override {
1907  buffer_operation op_data(blt_succ_cpy);
1908  op_data.svec = &v;
1909  my_aggregator.execute(&op_data);
1910  }
1911 
1912 #endif /* TBB_DEPRECATED_FLOW_NODE_EXTRACTION */
1913 
1915 
1918  r.remove_predecessor(*this);
1919  buffer_operation op_data(rem_succ);
1920  op_data.r = &r;
1921  my_aggregator.execute(&op_data);
1922  // even though this operation does not cause a forward, if we are the handler, and
1923  // a forward is scheduled, we may be the first to reach this point after the aggregator,
1924  // and so should check for the task.
1925  (void)enqueue_forwarding_task(op_data);
1926  return true;
1927  }
1928 
1930 
1932  bool try_get( T &v ) __TBB_override {
1933  buffer_operation op_data(req_item);
1934  op_data.elem = &v;
1935  my_aggregator.execute(&op_data);
1936  (void)enqueue_forwarding_task(op_data);
1937  return (op_data.status==internal::SUCCEEDED);
1938  }
1941 
1944  buffer_operation op_data(res_item);
1945  op_data.elem = &v;
1946  my_aggregator.execute(&op_data);
1947  (void)enqueue_forwarding_task(op_data);
1948  return (op_data.status==internal::SUCCEEDED);
1949  }
1954  buffer_operation op_data(rel_res);
1955  my_aggregator.execute(&op_data);
1956  (void)enqueue_forwarding_task(op_data);
1957  return true;
1958  }
1961 
1963  buffer_operation op_data(con_res);
1964  my_aggregator.execute(&op_data);
1965  (void)enqueue_forwarding_task(op_data);
1966  return true;
1967  }
1968 
1969 protected:
1970 
1971  template< typename R, typename B > friend class run_and_put_task;
1972  template<typename X, typename Y> friend class internal::broadcast_cache;
1973  template<typename X, typename Y> friend class internal::round_robin_cache;
1976  buffer_operation op_data(t, put_item);
1977  my_aggregator.execute(&op_data);
1978  task *ft = grab_forwarding_task(op_data);
1979  // sequencer_nodes can return failure (if an item has been previously inserted)
1980  // We have to spawn the returned task if our own operation fails.
1981 
1982  if(ft && op_data.status ==internal::FAILED) {
1983  // we haven't succeeded queueing the item, but for some reason the
1984  // call returned a task (if another request resulted in a successful
1985  // forward this could happen.) Queue the task and reset the pointer.
1986  internal::spawn_in_graph_arena(graph_reference(), *ft); ft = NULL;
1987  }
1988  else if(!ft && op_data.status ==internal::SUCCEEDED) {
1989  ft = SUCCESSFULLY_ENQUEUED;
1990  }
1991  return ft;
1992  }
1993 
1995  return my_graph;
1996  }
1999 
2000 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
2001 public:
2002  void extract() __TBB_override {
2003  my_built_predecessors.receiver_extract(*this);
2004  my_successors.built_successors().sender_extract(*this);
2005  }
2006 #endif
2007 
2008 protected:
2011  // TODO: just clear structures
2012  if (f&rf_clear_edges) {
2013  my_successors.clear();
2014 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
2015  my_built_predecessors.clear();
2016 #endif
2017  }
2018  forwarder_busy = false;
2019  }
2020 }; // buffer_node
2021 
2023 template <typename T, typename A=cache_aligned_allocator<T> >
2024 class queue_node : public buffer_node<T, A> {
2025 protected:
2030 
2031 private:
2032  template<typename, typename> friend class buffer_node;
2033 
2034  bool is_item_valid() {
2035  return this->my_item_valid(this->my_head);
2036  }
2037 
2038  void try_put_and_add_task(task*& last_task) {
2039  task *new_task = this->my_successors.try_put_task(this->front());
2040  if (new_task) {
2041  // workaround for icc bug
2042  graph& graph_ref = this->graph_reference();
2043  last_task = combine_tasks(graph_ref, last_task, new_task);
2044  this->destroy_front();
2045  }
2046  }
2047 
2048 protected:
2050  this->internal_forward_task_impl(op, this);
2051  }
2052 
2054  if ( this->my_reserved || !this->my_item_valid(this->my_head)){
2056  }
2057  else {
2058  this->pop_front(*(op->elem));
2060  }
2061  }
2063  if (this->my_reserved || !this->my_item_valid(this->my_head)) {
2065  }
2066  else {
2067  this->reserve_front(*(op->elem));
2069  }
2070  }
2072  this->consume_front();
2074  }
2075 
2076 public:
2077  typedef T input_type;
2078  typedef T output_type;
2081 
2083  explicit queue_node( graph &g ) : base_type(g) {
2084  tbb::internal::fgt_node( tbb::internal::FLOW_QUEUE_NODE, &(this->my_graph),
2085  static_cast<receiver<input_type> *>(this),
2086  static_cast<sender<output_type> *>(this) );
2087  }
2088 
2090  queue_node( const queue_node& src) : base_type(src) {
2091  tbb::internal::fgt_node( tbb::internal::FLOW_QUEUE_NODE, &(this->my_graph),
2092  static_cast<receiver<input_type> *>(this),
2093  static_cast<sender<output_type> *>(this) );
2094  }
2095 
2096 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
2097  void set_name( const char *name ) __TBB_override {
2099  }
2100 #endif
2101 
2102 protected:
2104  base_type::reset_node(f);
2105  }
2106 }; // queue_node
2107 
2109 template< typename T, typename A=cache_aligned_allocator<T> >
2110 class sequencer_node : public queue_node<T, A> {
2112  // my_sequencer should be a benign function and must be callable
2113  // from a parallel context. Does this mean it needn't be reset?
2114 public:
2115  typedef T input_type;
2116  typedef T output_type;
2119 
2121  template< typename Sequencer >
2122  sequencer_node( graph &g, const Sequencer& s ) : queue_node<T, A>(g),
2123  my_sequencer(new internal::function_body_leaf< T, size_t, Sequencer>(s) ) {
2124  tbb::internal::fgt_node( tbb::internal::FLOW_SEQUENCER_NODE, &(this->my_graph),
2125  static_cast<receiver<input_type> *>(this),
2126  static_cast<sender<output_type> *>(this) );
2127  }
2128 
2130  sequencer_node( const sequencer_node& src ) : queue_node<T, A>(src),
2131  my_sequencer( src.my_sequencer->clone() ) {
2132  tbb::internal::fgt_node( tbb::internal::FLOW_SEQUENCER_NODE, &(this->my_graph),
2133  static_cast<receiver<input_type> *>(this),
2134  static_cast<sender<output_type> *>(this) );
2135  }
2136 
2138  ~sequencer_node() { delete my_sequencer; }
2139 
2140 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
2141  void set_name( const char *name ) __TBB_override {
2143  }
2144 #endif
2145 
2146 protected:
2149 
2150 private:
2152  size_type tag = (*my_sequencer)(*(op->elem));
2153 #if !TBB_DEPRECATED_SEQUENCER_DUPLICATES
2154  if (tag < this->my_head) {
2155  // have already emitted a message with this tag
2157  return false;
2158  }
2159 #endif
2160  // cannot modify this->my_tail now; the buffer would be inconsistent.
2161  size_t new_tail = (tag+1 > this->my_tail) ? tag+1 : this->my_tail;
2162 
2163  if (this->size(new_tail) > this->capacity()) {
2164  this->grow_my_array(this->size(new_tail));
2165  }
2166  this->my_tail = new_tail;
2167 
2168  const internal::op_stat res = this->place_item(tag, *(op->elem)) ? internal::SUCCEEDED : internal::FAILED;
2169  __TBB_store_with_release(op->status, res);
2170  return res ==internal::SUCCEEDED;
2171  }
2172 }; // sequencer_node
2173 
2175 template< typename T, typename Compare = std::less<T>, typename A=cache_aligned_allocator<T> >
2176 class priority_queue_node : public buffer_node<T, A> {
2177 public:
2178  typedef T input_type;
2179  typedef T output_type;
2184 
2186  explicit priority_queue_node( graph &g ) : buffer_node<T, A>(g), mark(0) {
2187  tbb::internal::fgt_node( tbb::internal::FLOW_PRIORITY_QUEUE_NODE, &(this->my_graph),
2188  static_cast<receiver<input_type> *>(this),
2189  static_cast<sender<output_type> *>(this) );
2190  }
2191 
2193  priority_queue_node( const priority_queue_node &src ) : buffer_node<T, A>(src), mark(0) {
2194  tbb::internal::fgt_node( tbb::internal::FLOW_PRIORITY_QUEUE_NODE, &(this->my_graph),
2195  static_cast<receiver<input_type> *>(this),
2196  static_cast<sender<output_type> *>(this) );
2197  }
2198 
2199 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
2200  void set_name( const char *name ) __TBB_override {
2202  }
2203 #endif
2204 
2205 protected:
2206 
2208  mark = 0;
2209  base_type::reset_node(f);
2210  }
2211 
2215 
2218  this->internal_forward_task_impl(op, this);
2219  }
2220 
2222  this->handle_operations_impl(op_list, this);
2223  }
2224 
2226  prio_push(*(op->elem));
2228  return true;
2229  }
2230 
2232  // if empty or already reserved, don't pop
2233  if ( this->my_reserved == true || this->my_tail == 0 ) {
2235  return;
2236  }
2237 
2238  *(op->elem) = prio();
2240  prio_pop();
2241 
2242  }
2243 
2244  // pops the highest-priority item, saves copy
2246  if (this->my_reserved == true || this->my_tail == 0) {
2248  return;
2249  }
2250  this->my_reserved = true;
2251  *(op->elem) = prio();
2252  reserved_item = *(op->elem);
2254  prio_pop();
2255  }
2256 
2259  this->my_reserved = false;
2260  reserved_item = input_type();
2261  }
2262 
2265  prio_push(reserved_item);
2266  this->my_reserved = false;
2267  reserved_item = input_type();
2268  }
2269 
2270 private:
2271  template<typename, typename> friend class buffer_node;
2272 
2273  void order() {
2274  if (mark < this->my_tail) heapify();
2275  __TBB_ASSERT(mark == this->my_tail, "mark unequal after heapify");
2276  }
2277 
2278  bool is_item_valid() {
2279  return this->my_tail > 0;
2280  }
2281 
2282  void try_put_and_add_task(task*& last_task) {
2283  task * new_task = this->my_successors.try_put_task(this->prio());
2284  if (new_task) {
2285  // workaround for icc bug
2286  graph& graph_ref = this->graph_reference();
2287  last_task = combine_tasks(graph_ref, last_task, new_task);
2288  prio_pop();
2289  }
2290  }
2291 
2292 private:
2293  Compare compare;
2295 
2297 
2298  // in case a reheap has not been done after a push, check if the mark item is higher than the 0'th item
2299  bool prio_use_tail() {
2300  __TBB_ASSERT(mark <= this->my_tail, "mark outside bounds before test");
2301  return mark < this->my_tail && compare(this->get_my_item(0), this->get_my_item(this->my_tail - 1));
2302  }
2303 
2304  // prio_push: checks that the item will fit, expand array if necessary, put at end
2305  void prio_push(const T &src) {
2306  if ( this->my_tail >= this->my_array_size )
2307  this->grow_my_array( this->my_tail + 1 );
2308  (void) this->place_item(this->my_tail, src);
2309  ++(this->my_tail);
2310  __TBB_ASSERT(mark < this->my_tail, "mark outside bounds after push");
2311  }
2312 
2313  // prio_pop: deletes highest priority item from the array, and if it is item
2314  // 0, move last item to 0 and reheap. If end of array, just destroy and decrement tail
2315  // and mark. Assumes the array has already been tested for emptiness; no failure.
2316  void prio_pop() {
2317  if (prio_use_tail()) {
2318  // there are newly pushed elements; last one higher than top
2319  // copy the data
2320  this->destroy_item(this->my_tail-1);
2321  --(this->my_tail);
2322  __TBB_ASSERT(mark <= this->my_tail, "mark outside bounds after pop");
2323  return;
2324  }
2325  this->destroy_item(0);
2326  if(this->my_tail > 1) {
2327  // push the last element down heap
2328  __TBB_ASSERT(this->my_item_valid(this->my_tail - 1), NULL);
2329  this->move_item(0,this->my_tail - 1);
2330  }
2331  --(this->my_tail);
2332  if(mark > this->my_tail) --mark;
2333  if (this->my_tail > 1) // don't reheap for heap of size 1
2334  reheap();
2335  __TBB_ASSERT(mark <= this->my_tail, "mark outside bounds after pop");
2336  }
2337 
2338  const T& prio() {
2339  return this->get_my_item(prio_use_tail() ? this->my_tail-1 : 0);
2340  }
2341 
2342  // turn array into heap
2343  void heapify() {
2344  if(this->my_tail == 0) {
2345  mark = 0;
2346  return;
2347  }
2348  if (!mark) mark = 1;
2349  for (; mark<this->my_tail; ++mark) { // for each unheaped element
2350  size_type cur_pos = mark;
2351  input_type to_place;
2352  this->fetch_item(mark,to_place);
2353  do { // push to_place up the heap
2354  size_type parent = (cur_pos-1)>>1;
2355  if (!compare(this->get_my_item(parent), to_place))
2356  break;
2357  this->move_item(cur_pos, parent);
2358  cur_pos = parent;
2359  } while( cur_pos );
2360  (void) this->place_item(cur_pos, to_place);
2361  }
2362  }
2363 
2364  // otherwise heapified array with new root element; rearrange to heap
2365  void reheap() {
2366  size_type cur_pos=0, child=1;
2367  while (child < mark) {
2368  size_type target = child;
2369  if (child+1<mark &&
2370  compare(this->get_my_item(child),
2371  this->get_my_item(child+1)))
2372  ++target;
2373  // target now has the higher priority child
2374  if (compare(this->get_my_item(target),
2375  this->get_my_item(cur_pos)))
2376  break;
2377  // swap
2378  this->swap_items(cur_pos, target);
2379  cur_pos = target;
2380  child = (cur_pos<<1)+1;
2381  }
2382  }
2383 }; // priority_queue_node
2384 
2386 
2389 template< typename T >
2390 class limiter_node : public graph_node, public receiver< T >, public sender< T > {
2391 public:
2392  typedef T input_type;
2393  typedef T output_type;
2396 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
2397  typedef typename receiver<input_type>::built_predecessors_type built_predecessors_type;
2398  typedef typename sender<output_type>::built_successors_type built_successors_type;
2399  typedef typename receiver<input_type>::predecessor_list_type predecessor_list_type;
2400  typedef typename sender<output_type>::successor_list_type successor_list_type;
2401 #endif
2402  //TODO: There is a lack of predefined types for its controlling "decrementer" port. It should be fixed later.
2403 
2404 private:
2406  size_t my_count; //number of successful puts
2407  size_t my_tries; //number of active put attempts
2412 
2414 
2415  // Let decrementer call decrement_counter()
2417 
2418  bool check_conditions() { // always called under lock
2419  return ( my_count + my_tries < my_threshold && !my_predecessors.empty() && !my_successors.empty() );
2420  }
2421 
2422  // only returns a valid task pointer or NULL, never SUCCESSFULLY_ENQUEUED
2424  input_type v;
2425  task *rval = NULL;
2426  bool reserved = false;
2427  {
2428  spin_mutex::scoped_lock lock(my_mutex);
2429  if ( check_conditions() )
2430  ++my_tries;
2431  else
2432  return NULL;
2433  }
2434 
2435  //SUCCESS
2436  // if we can reserve and can put, we consume the reservation
2437  // we increment the count and decrement the tries
2438  if ( (my_predecessors.try_reserve(v)) == true ){
2439  reserved=true;
2440  if ( (rval = my_successors.try_put_task(v)) != NULL ){
2441  {
2442  spin_mutex::scoped_lock lock(my_mutex);
2443  ++my_count;
2444  --my_tries;
2445  my_predecessors.try_consume();
2446  if ( check_conditions() ) {
2447  if ( internal::is_graph_active(this->my_graph) ) {
2448  task *rtask = new ( task::allocate_additional_child_of( *(this->my_graph.root_task()) ) )
2451  }
2452  }
2453  }
2454  return rval;
2455  }
2456  }
2457  //FAILURE
2458  //if we can't reserve, we decrement the tries
2459  //if we can reserve but can't put, we decrement the tries and release the reservation
2460  {
2461  spin_mutex::scoped_lock lock(my_mutex);
2462  --my_tries;
2463  if (reserved) my_predecessors.try_release();
2464  if ( check_conditions() ) {
2465  if ( internal::is_graph_active(this->my_graph) ) {
2466  task *rtask = new ( task::allocate_additional_child_of( *(this->my_graph.root_task()) ) )
2468  __TBB_ASSERT(!rval, "Have two tasks to handle");
2469  return rtask;
2470  }
2471  }
2472  return rval;
2473  }
2474  }
2475 
2476  void forward() {
2477  __TBB_ASSERT(false, "Should never be called");
2478  return;
2479  }
2480 
2482  {
2483  spin_mutex::scoped_lock lock(my_mutex);
2484  if(my_count) --my_count;
2485  }
2486  return forward_task();
2487  }
2488 
2489 public:
2492 
2494  limiter_node(graph &g, size_t threshold, int num_decrement_predecessors=0) :
2495  graph_node(g), my_threshold(threshold), my_count(0), my_tries(0),
2496  init_decrement_predecessors(num_decrement_predecessors),
2497  decrement(num_decrement_predecessors)
2498  {
2499  my_predecessors.set_owner(this);
2500  my_successors.set_owner(this);
2501  decrement.set_owner(this);
2502  tbb::internal::fgt_node( tbb::internal::FLOW_LIMITER_NODE, &this->my_graph,
2503  static_cast<receiver<input_type> *>(this), static_cast<receiver<continue_msg> *>(&decrement),
2504  static_cast<sender<output_type> *>(this) );
2505  }
2506 
2508  limiter_node( const limiter_node& src ) :
2509  graph_node(src.my_graph), receiver<T>(), sender<T>(),
2510  my_threshold(src.my_threshold), my_count(0), my_tries(0),
2511  init_decrement_predecessors(src.init_decrement_predecessors),
2512  decrement(src.init_decrement_predecessors)
2513  {
2514  my_predecessors.set_owner(this);
2515  my_successors.set_owner(this);
2516  decrement.set_owner(this);
2517  tbb::internal::fgt_node( tbb::internal::FLOW_LIMITER_NODE, &this->my_graph,
2518  static_cast<receiver<input_type> *>(this), static_cast<receiver<continue_msg> *>(&decrement),
2519  static_cast<sender<output_type> *>(this) );
2520  }
2521 
2522 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
2523  void set_name( const char *name ) __TBB_override {
2525  }
2526 #endif
2527 
2530  spin_mutex::scoped_lock lock(my_mutex);
2531  bool was_empty = my_successors.empty();
2532  my_successors.register_successor(r);
2533  //spawn a forward task if this is the only successor
2534  if ( was_empty && !my_predecessors.empty() && my_count + my_tries < my_threshold ) {
2535  if ( internal::is_graph_active(this->my_graph) ) {
2536  task* task = new ( task::allocate_additional_child_of( *(this->my_graph.root_task()) ) )
2539  }
2540  }
2541  return true;
2542  }
2543 
2545 
2547  r.remove_predecessor(*this);
2548  my_successors.remove_successor(r);
2549  return true;
2550  }
2551 
2552 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
2553  built_successors_type &built_successors() __TBB_override { return my_successors.built_successors(); }
2554  built_predecessors_type &built_predecessors() __TBB_override { return my_predecessors.built_predecessors(); }
2555 
2556  void internal_add_built_successor(successor_type &src) __TBB_override {
2557  my_successors.internal_add_built_successor(src);
2558  }
2559 
2560  void internal_delete_built_successor(successor_type &src) __TBB_override {
2561  my_successors.internal_delete_built_successor(src);
2562  }
2563 
2564  size_t successor_count() __TBB_override { return my_successors.successor_count(); }
2565 
2566  void copy_successors(successor_list_type &v) __TBB_override {
2567  my_successors.copy_successors(v);
2568  }
2569 
2570  void internal_add_built_predecessor(predecessor_type &src) __TBB_override {
2571  my_predecessors.internal_add_built_predecessor(src);
2572  }
2573 
2574  void internal_delete_built_predecessor(predecessor_type &src) __TBB_override {
2575  my_predecessors.internal_delete_built_predecessor(src);
2576  }
2577 
2578  size_t predecessor_count() __TBB_override { return my_predecessors.predecessor_count(); }
2579 
2580  void copy_predecessors(predecessor_list_type &v) __TBB_override {
2581  my_predecessors.copy_predecessors(v);
2582  }
2583 
2584  void extract() __TBB_override {
2585  my_count = 0;
2586  my_successors.built_successors().sender_extract(*this);
2587  my_predecessors.built_predecessors().receiver_extract(*this);
2588  decrement.built_predecessors().receiver_extract(decrement);
2589  }
2590 #endif /* TBB_DEPRECATED_FLOW_NODE_EXTRACTION */
2591 
2594  spin_mutex::scoped_lock lock(my_mutex);
2595  my_predecessors.add( src );
2596  if ( my_count + my_tries < my_threshold && !my_successors.empty() && internal::is_graph_active(this->my_graph) ) {
2597  task* task = new ( task::allocate_additional_child_of( *(this->my_graph.root_task()) ) )
2600  }
2601  return true;
2602  }
2603 
2606  my_predecessors.remove( src );
2607  return true;
2608  }
2609 
2610 protected:
2611 
2612  template< typename R, typename B > friend class run_and_put_task;
2613  template<typename X, typename Y> friend class internal::broadcast_cache;
2614  template<typename X, typename Y> friend class internal::round_robin_cache;
2617  {
2619  if ( my_count + my_tries >= my_threshold )
2620  return NULL;
2621  else
2622  ++my_tries;
2623  }
2624 
2625  task * rtask = my_successors.try_put_task(t);
2626 
2627  if ( !rtask ) { // try_put_task failed.
2629  --my_tries;
2630  if (check_conditions() && internal::is_graph_active(this->my_graph)) {
2631  rtask = new ( task::allocate_additional_child_of( *(this->my_graph.root_task()) ) )
2633  }
2634  }
2635  else {
2637  ++my_count;
2638  --my_tries;
2639  }
2640  return rtask;
2641  }
2642 
2644  return my_graph;
2645  }
2646 
2648  __TBB_ASSERT(false,NULL); // should never be called
2649  }
2650 
2652  my_count = 0;
2653  if(f & rf_clear_edges) {
2654  my_predecessors.clear();
2655  my_successors.clear();
2656  }
2657  else
2658  {
2659  my_predecessors.reset( );
2660  }
2661  decrement.reset_receiver(f);
2662  }
2663 }; // limiter_node
2664 
2666 
2670 using internal::input_port;
2671 using internal::tag_value;
2672 
2673 template<typename OutputTuple, typename JP=queueing> class join_node;
2674 
2675 template<typename OutputTuple>
2676 class join_node<OutputTuple,reserving>: public internal::unfolded_join_node<tbb::flow::tuple_size<OutputTuple>::value, reserving_port, OutputTuple, reserving> {
2677 private:
2680 public:
2681  typedef OutputTuple output_type;
2683  explicit join_node(graph &g) : unfolded_type(g) {
2684  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_JOIN_NODE_RESERVING, &this->my_graph,
2685  this->input_ports(), static_cast< sender< output_type > *>(this) );
2686  }
2687  join_node(const join_node &other) : unfolded_type(other) {
2688  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_JOIN_NODE_RESERVING, &this->my_graph,
2689  this->input_ports(), static_cast< sender< output_type > *>(this) );
2690  }
2691 
2692 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
2693  void set_name( const char *name ) __TBB_override {
2695  }
2696 #endif
2697 
2698 };
2699 
2700 template<typename OutputTuple>
2701 class join_node<OutputTuple,queueing>: public internal::unfolded_join_node<tbb::flow::tuple_size<OutputTuple>::value, queueing_port, OutputTuple, queueing> {
2702 private:
2705 public:
2706  typedef OutputTuple output_type;
2708  explicit join_node(graph &g) : unfolded_type(g) {
2709  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_JOIN_NODE_QUEUEING, &this->my_graph,
2710  this->input_ports(), static_cast< sender< output_type > *>(this) );
2711  }
2712  join_node(const join_node &other) : unfolded_type(other) {
2713  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_JOIN_NODE_QUEUEING, &this->my_graph,
2714  this->input_ports(), static_cast< sender< output_type > *>(this) );
2715  }
2716 
2717 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
2718  void set_name( const char *name ) __TBB_override {
2720  }
2721 #endif
2722 
2723 };
2724 
2725 // template for key_matching join_node
2726 // tag_matching join_node is a specialization of key_matching, and is source-compatible.
2727 template<typename OutputTuple, typename K, typename KHash>
2728 class join_node<OutputTuple, key_matching<K, KHash> > : public internal::unfolded_join_node<tbb::flow::tuple_size<OutputTuple>::value,
2729  key_matching_port, OutputTuple, key_matching<K,KHash> > {
2730 private:
2733 public:
2734  typedef OutputTuple output_type;
2736 
2737 #if __TBB_PREVIEW_MESSAGE_BASED_KEY_MATCHING
2739 #endif /* __TBB_PREVIEW_MESSAGE_BASED_KEY_MATCHING */
2740 
2741  template<typename __TBB_B0, typename __TBB_B1>
2742  join_node(graph &g, __TBB_B0 b0, __TBB_B1 b1) : unfolded_type(g, b0, b1) {
2743  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_JOIN_NODE_TAG_MATCHING, &this->my_graph,
2744  this->input_ports(), static_cast< sender< output_type > *>(this) );
2745  }
2746  template<typename __TBB_B0, typename __TBB_B1, typename __TBB_B2>
2747  join_node(graph &g, __TBB_B0 b0, __TBB_B1 b1, __TBB_B2 b2) : unfolded_type(g, b0, b1, b2) {
2748  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_JOIN_NODE_TAG_MATCHING, &this->my_graph,
2749  this->input_ports(), static_cast< sender< output_type > *>(this) );
2750  }
2751  template<typename __TBB_B0, typename __TBB_B1, typename __TBB_B2, typename __TBB_B3>
2752  join_node(graph &g, __TBB_B0 b0, __TBB_B1 b1, __TBB_B2 b2, __TBB_B3 b3) : unfolded_type(g, b0, b1, b2, b3) {
2753  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_JOIN_NODE_TAG_MATCHING, &this->my_graph,
2754  this->input_ports(), static_cast< sender< output_type > *>(this) );
2755  }
2756  template<typename __TBB_B0, typename __TBB_B1, typename __TBB_B2, typename __TBB_B3, typename __TBB_B4>
2757  join_node(graph &g, __TBB_B0 b0, __TBB_B1 b1, __TBB_B2 b2, __TBB_B3 b3, __TBB_B4 b4) :
2758  unfolded_type(g, b0, b1, b2, b3, b4) {
2759  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_JOIN_NODE_TAG_MATCHING, &this->my_graph,
2760  this->input_ports(), static_cast< sender< output_type > *>(this) );
2761  }
2762 #if __TBB_VARIADIC_MAX >= 6
2763  template<typename __TBB_B0, typename __TBB_B1, typename __TBB_B2, typename __TBB_B3, typename __TBB_B4,
2764  typename __TBB_B5>
2765  join_node(graph &g, __TBB_B0 b0, __TBB_B1 b1, __TBB_B2 b2, __TBB_B3 b3, __TBB_B4 b4, __TBB_B5 b5) :
2766  unfolded_type(g, b0, b1, b2, b3, b4, b5) {
2767  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_JOIN_NODE_TAG_MATCHING, &this->my_graph,
2768  this->input_ports(), static_cast< sender< output_type > *>(this) );
2769  }
2770 #endif
2771 #if __TBB_VARIADIC_MAX >= 7
2772  template<typename __TBB_B0, typename __TBB_B1, typename __TBB_B2, typename __TBB_B3, typename __TBB_B4,
2773  typename __TBB_B5, typename __TBB_B6>
2774  join_node(graph &g, __TBB_B0 b0, __TBB_B1 b1, __TBB_B2 b2, __TBB_B3 b3, __TBB_B4 b4, __TBB_B5 b5, __TBB_B6 b6) :
2775  unfolded_type(g, b0, b1, b2, b3, b4, b5, b6) {
2776  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_JOIN_NODE_TAG_MATCHING, &this->my_graph,
2777  this->input_ports(), static_cast< sender< output_type > *>(this) );
2778  }
2779 #endif
2780 #if __TBB_VARIADIC_MAX >= 8
2781  template<typename __TBB_B0, typename __TBB_B1, typename __TBB_B2, typename __TBB_B3, typename __TBB_B4,
2782  typename __TBB_B5, typename __TBB_B6, typename __TBB_B7>
2783  join_node(graph &g, __TBB_B0 b0, __TBB_B1 b1, __TBB_B2 b2, __TBB_B3 b3, __TBB_B4 b4, __TBB_B5 b5, __TBB_B6 b6,
2784  __TBB_B7 b7) : unfolded_type(g, b0, b1, b2, b3, b4, b5, b6, b7) {
2785  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_JOIN_NODE_TAG_MATCHING, &this->my_graph,
2786  this->input_ports(), static_cast< sender< output_type > *>(this) );
2787  }
2788 #endif
2789 #if __TBB_VARIADIC_MAX >= 9
2790  template<typename __TBB_B0, typename __TBB_B1, typename __TBB_B2, typename __TBB_B3, typename __TBB_B4,
2791  typename __TBB_B5, typename __TBB_B6, typename __TBB_B7, typename __TBB_B8>
2792  join_node(graph &g, __TBB_B0 b0, __TBB_B1 b1, __TBB_B2 b2, __TBB_B3 b3, __TBB_B4 b4, __TBB_B5 b5, __TBB_B6 b6,
2793  __TBB_B7 b7, __TBB_B8 b8) : unfolded_type(g, b0, b1, b2, b3, b4, b5, b6, b7, b8) {
2794  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_JOIN_NODE_TAG_MATCHING, &this->my_graph,
2795  this->input_ports(), static_cast< sender< output_type > *>(this) );
2796  }
2797 #endif
2798 #if __TBB_VARIADIC_MAX >= 10
2799  template<typename __TBB_B0, typename __TBB_B1, typename __TBB_B2, typename __TBB_B3, typename __TBB_B4,
2800  typename __TBB_B5, typename __TBB_B6, typename __TBB_B7, typename __TBB_B8, typename __TBB_B9>
2801  join_node(graph &g, __TBB_B0 b0, __TBB_B1 b1, __TBB_B2 b2, __TBB_B3 b3, __TBB_B4 b4, __TBB_B5 b5, __TBB_B6 b6,
2802  __TBB_B7 b7, __TBB_B8 b8, __TBB_B9 b9) : unfolded_type(g, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9) {
2803  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_JOIN_NODE_TAG_MATCHING, &this->my_graph,
2804  this->input_ports(), static_cast< sender< output_type > *>(this) );
2805  }
2806 #endif
2807  join_node(const join_node &other) : unfolded_type(other) {
2808  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_JOIN_NODE_TAG_MATCHING, &this->my_graph,
2809  this->input_ports(), static_cast< sender< output_type > *>(this) );
2810  }
2811 
2812 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
2813  void set_name( const char *name ) __TBB_override {
2815  }
2816 #endif
2817 
2818 };
2819 
2820 // indexer node
2822 
2823 // TODO: Implement interface with variadic template or tuple
2824 template<typename T0, typename T1=null_type, typename T2=null_type, typename T3=null_type,
2825  typename T4=null_type, typename T5=null_type, typename T6=null_type,
2826  typename T7=null_type, typename T8=null_type, typename T9=null_type> class indexer_node;
2827 
2828 //indexer node specializations
2829 template<typename T0>
2830 class indexer_node<T0> : public internal::unfolded_indexer_node<tuple<T0> > {
2831 private:
2832  static const int N = 1;
2833 public:
2834  typedef tuple<T0> InputTuple;
2838  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_INDEXER_NODE, &this->my_graph,
2839  this->input_ports(), static_cast< sender< output_type > *>(this) );
2840  }
2841  // Copy constructor
2842  indexer_node( const indexer_node& other ) : unfolded_type(other) {
2843  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_INDEXER_NODE, &this->my_graph,
2844  this->input_ports(), static_cast< sender< output_type > *>(this) );
2845  }
2846 
2847 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
2848  void set_name( const char *name ) __TBB_override {
2850  }
2851 #endif
2852 };
2853 
2854 template<typename T0, typename T1>
2855 class indexer_node<T0, T1> : public internal::unfolded_indexer_node<tuple<T0, T1> > {
2856 private:
2857  static const int N = 2;
2858 public:
2859  typedef tuple<T0, T1> InputTuple;
2863  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_INDEXER_NODE, &this->my_graph,
2864  this->input_ports(), static_cast< sender< output_type > *>(this) );
2865  }
2866  // Copy constructor
2867  indexer_node( const indexer_node& other ) : unfolded_type(other) {
2868  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_INDEXER_NODE, &this->my_graph,
2869  this->input_ports(), static_cast< sender< output_type > *>(this) );
2870  }
2871 
2872 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
2873  void set_name( const char *name ) __TBB_override {
2875  }
2876 #endif
2877 };
2878 
2879 template<typename T0, typename T1, typename T2>
2880 class indexer_node<T0, T1, T2> : public internal::unfolded_indexer_node<tuple<T0, T1, T2> > {
2881 private:
2882  static const int N = 3;
2883 public:
2884  typedef tuple<T0, T1, T2> InputTuple;
2888  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_INDEXER_NODE, &this->my_graph,
2889  this->input_ports(), static_cast< sender< output_type > *>(this) );
2890  }
2891  // Copy constructor
2892  indexer_node( const indexer_node& other ) : unfolded_type(other) {
2893  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_INDEXER_NODE, &this->my_graph,
2894  this->input_ports(), static_cast< sender< output_type > *>(this) );
2895  }
2896 
2897 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
2898  void set_name( const char *name ) __TBB_override {
2900  }
2901 #endif
2902 };
2903 
2904 template<typename T0, typename T1, typename T2, typename T3>
2905 class indexer_node<T0, T1, T2, T3> : public internal::unfolded_indexer_node<tuple<T0, T1, T2, T3> > {
2906 private:
2907  static const int N = 4;
2908 public:
2909  typedef tuple<T0, T1, T2, T3> InputTuple;
2913  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_INDEXER_NODE, &this->my_graph,
2914  this->input_ports(), static_cast< sender< output_type > *>(this) );
2915  }
2916  // Copy constructor
2917  indexer_node( const indexer_node& other ) : unfolded_type(other) {
2918  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_INDEXER_NODE, &this->my_graph,
2919  this->input_ports(), static_cast< sender< output_type > *>(this) );
2920  }
2921 
2922 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
2923  void set_name( const char *name ) __TBB_override {
2925  }
2926 #endif
2927 };
2928 
2929 template<typename T0, typename T1, typename T2, typename T3, typename T4>
2930 class indexer_node<T0, T1, T2, T3, T4> : public internal::unfolded_indexer_node<tuple<T0, T1, T2, T3, T4> > {
2931 private:
2932  static const int N = 5;
2933 public:
2934  typedef tuple<T0, T1, T2, T3, T4> InputTuple;
2938  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_INDEXER_NODE, &this->my_graph,
2939  this->input_ports(), static_cast< sender< output_type > *>(this) );
2940  }
2941  // Copy constructor
2942  indexer_node( const indexer_node& other ) : unfolded_type(other) {
2943  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_INDEXER_NODE, &this->my_graph,
2944  this->input_ports(), static_cast< sender< output_type > *>(this) );
2945  }
2946 
2947 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
2948  void set_name( const char *name ) __TBB_override {
2950  }
2951 #endif
2952 };
2953 
2954 #if __TBB_VARIADIC_MAX >= 6
2955 template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5>
2956 class indexer_node<T0, T1, T2, T3, T4, T5> : public internal::unfolded_indexer_node<tuple<T0, T1, T2, T3, T4, T5> > {
2957 private:
2958  static const int N = 6;
2959 public:
2960  typedef tuple<T0, T1, T2, T3, T4, T5> InputTuple;
2964  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_INDEXER_NODE, &this->my_graph,
2965  this->input_ports(), static_cast< sender< output_type > *>(this) );
2966  }
2967  // Copy constructor
2968  indexer_node( const indexer_node& other ) : unfolded_type(other) {
2969  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_INDEXER_NODE, &this->my_graph,
2970  this->input_ports(), static_cast< sender< output_type > *>(this) );
2971  }
2972 
2973 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
2974  void set_name( const char *name ) __TBB_override {
2976  }
2977 #endif
2978 };
2979 #endif //variadic max 6
2980 
2981 #if __TBB_VARIADIC_MAX >= 7
2982 template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5,
2983  typename T6>
2984 class indexer_node<T0, T1, T2, T3, T4, T5, T6> : public internal::unfolded_indexer_node<tuple<T0, T1, T2, T3, T4, T5, T6> > {
2985 private:
2986  static const int N = 7;
2987 public:
2988  typedef tuple<T0, T1, T2, T3, T4, T5, T6> InputTuple;
2992  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_INDEXER_NODE, &this->my_graph,
2993  this->input_ports(), static_cast< sender< output_type > *>(this) );
2994  }
2995  // Copy constructor
2996  indexer_node( const indexer_node& other ) : unfolded_type(other) {
2997  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_INDEXER_NODE, &this->my_graph,
2998  this->input_ports(), static_cast< sender< output_type > *>(this) );
2999  }
3000 
3001 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
3002  void set_name( const char *name ) __TBB_override {
3004  }
3005 #endif
3006 };
3007 #endif //variadic max 7
3008 
3009 #if __TBB_VARIADIC_MAX >= 8
3010 template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5,
3011  typename T6, typename T7>
3012 class indexer_node<T0, T1, T2, T3, T4, T5, T6, T7> : public internal::unfolded_indexer_node<tuple<T0, T1, T2, T3, T4, T5, T6, T7> > {
3013 private:
3014  static const int N = 8;
3015 public:
3016  typedef tuple<T0, T1, T2, T3, T4, T5, T6, T7> InputTuple;
3020  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_INDEXER_NODE, &this->my_graph,
3021  this->input_ports(), static_cast< sender< output_type > *>(this) );
3022  }
3023  // Copy constructor
3024  indexer_node( const indexer_node& other ) : unfolded_type(other) {
3025  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_INDEXER_NODE, &this->my_graph,
3026  this->input_ports(), static_cast< sender< output_type > *>(this) );
3027  }
3028 
3029 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
3030  void set_name( const char *name ) __TBB_override {
3032  }
3033 #endif
3034 };
3035 #endif //variadic max 8
3036 
3037 #if __TBB_VARIADIC_MAX >= 9
3038 template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5,
3039  typename T6, typename T7, typename T8>
3040 class indexer_node<T0, T1, T2, T3, T4, T5, T6, T7, T8> : public internal::unfolded_indexer_node<tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8> > {
3041 private:
3042  static const int N = 9;
3043 public:
3044  typedef tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8> InputTuple;
3048  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_INDEXER_NODE, &this->my_graph,
3049  this->input_ports(), static_cast< sender< output_type > *>(this) );
3050  }
3051  // Copy constructor
3052  indexer_node( const indexer_node& other ) : unfolded_type(other) {
3053  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_INDEXER_NODE, &this->my_graph,
3054  this->input_ports(), static_cast< sender< output_type > *>(this) );
3055  }
3056 
3057 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
3058  void set_name( const char *name ) __TBB_override {
3060  }
3061 #endif
3062 };
3063 #endif //variadic max 9
3064 
3065 #if __TBB_VARIADIC_MAX >= 10
3066 template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5,
3067  typename T6, typename T7, typename T8, typename T9>
3068 class indexer_node/*default*/ : public internal::unfolded_indexer_node<tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> > {
3069 private:
3070  static const int N = 10;
3071 public:
3072  typedef tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> InputTuple;
3076  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_INDEXER_NODE, &this->my_graph,
3077  this->input_ports(), static_cast< sender< output_type > *>(this) );
3078  }
3079  // Copy constructor
3080  indexer_node( const indexer_node& other ) : unfolded_type(other) {
3081  tbb::internal::fgt_multiinput_node<N>( tbb::internal::FLOW_INDEXER_NODE, &this->my_graph,
3082  this->input_ports(), static_cast< sender< output_type > *>(this) );
3083  }
3084 
3085 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
3086  void set_name( const char *name ) __TBB_override {
3088  }
3089 #endif
3090 };
3091 #endif //variadic max 10
3092 
3093 #if __TBB_PREVIEW_ASYNC_MSG
3095 #else
3096 template< typename T >
3097 inline void internal_make_edge( sender<T> &p, receiver<T> &s ) {
3098 #endif
3099 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
3100  s.internal_add_built_predecessor(p);
3101  p.internal_add_built_successor(s);
3102 #endif
3103  p.register_successor( s );
3105 }
3106 
3108 template< typename T >
3109 inline void make_edge( sender<T> &p, receiver<T> &s ) {
3110  internal_make_edge( p, s );
3111 }
3112 
3113 #if __TBB_PREVIEW_ASYNC_MSG
3114 template< typename TS, typename TR,
3117 inline void make_edge( TS &p, TR &s ) {
3118  internal_make_edge( p, s );
3119 }
3120 
3121 template< typename T >
3123  internal_make_edge( p, s );
3124 }
3125 
3126 template< typename T >
3128  internal_make_edge( p, s );
3129 }
3130 
3131 #endif // __TBB_PREVIEW_ASYNC_MSG
3132 
3133 #if __TBB_FLOW_GRAPH_CPP11_FEATURES
3134 //Makes an edge from port 0 of a multi-output predecessor to port 0 of a multi-input successor.
3135 template< typename T, typename V,
3136  typename = typename T::output_ports_type, typename = typename V::input_ports_type >
3137 inline void make_edge( T& output, V& input) {
3138  make_edge(get<0>(output.output_ports()), get<0>(input.input_ports()));
3139 }
3140 
3141 //Makes an edge from port 0 of a multi-output predecessor to a receiver.
3142 template< typename T, typename R,
3143  typename = typename T::output_ports_type >
3144 inline void make_edge( T& output, receiver<R>& input) {
3145  make_edge(get<0>(output.output_ports()), input);
3146 }
3147 
3148 //Makes an edge from a sender to port 0 of a multi-input successor.
3149 template< typename S, typename V,
3150  typename = typename V::input_ports_type >
3151 inline void make_edge( sender<S>& output, V& input) {
3152  make_edge(output, get<0>(input.input_ports()));
3153 }
3154 #endif
3155 
3156 #if __TBB_PREVIEW_ASYNC_MSG
3158 #else
3159 template< typename T >
3160 inline void internal_remove_edge( sender<T> &p, receiver<T> &s ) {
3161 #endif
3162  p.remove_successor( s );
3163 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
3164  // TODO: should we try to remove p from the predecessor list of s, in case the edge is reversed?
3165  p.internal_delete_built_successor(s);
3166  s.internal_delete_built_predecessor(p);
3167 #endif
3169 }
3170 
3172 template< typename T >
3173 inline void remove_edge( sender<T> &p, receiver<T> &s ) {
3174  internal_remove_edge( p, s );
3175 }
3176 
3177 #if __TBB_PREVIEW_ASYNC_MSG
3178 template< typename TS, typename TR,
3181 inline void remove_edge( TS &p, TR &s ) {
3182  internal_remove_edge( p, s );
3183 }
3184 
3185 template< typename T >
3187  internal_remove_edge( p, s );
3188 }
3189 
3190 template< typename T >
3192  internal_remove_edge( p, s );
3193 }
3194 #endif // __TBB_PREVIEW_ASYNC_MSG
3195 
3196 #if __TBB_FLOW_GRAPH_CPP11_FEATURES
3197 //Removes an edge between port 0 of a multi-output predecessor and port 0 of a multi-input successor.
3198 template< typename T, typename V,
3199  typename = typename T::output_ports_type, typename = typename V::input_ports_type >
3200 inline void remove_edge( T& output, V& input) {
3201  remove_edge(get<0>(output.output_ports()), get<0>(input.input_ports()));
3202 }
3203 
3204 //Removes an edge between port 0 of a multi-output predecessor and a receiver.
3205 template< typename T, typename R,
3206  typename = typename T::output_ports_type >
3207 inline void remove_edge( T& output, receiver<R>& input) {
3208  remove_edge(get<0>(output.output_ports()), input);
3209 }
3210 //Removes an edge between a sender and port 0 of a multi-input successor.
3211 template< typename S, typename V,
3212  typename = typename V::input_ports_type >
3213 inline void remove_edge( sender<S>& output, V& input) {
3214  remove_edge(output, get<0>(input.input_ports()));
3215 }
3216 #endif
3217 
3218 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
3219 template<typename C >
3220 template< typename S >
3221 void internal::edge_container<C>::sender_extract( S &s ) {
3222  edge_list_type e = built_edges;
3223  for ( typename edge_list_type::iterator i = e.begin(); i != e.end(); ++i ) {
3224  remove_edge(s, **i);
3225  }
3226 }
3227 
3228 template<typename C >
3229 template< typename R >
3230 void internal::edge_container<C>::receiver_extract( R &r ) {
3231  edge_list_type e = built_edges;
3232  for ( typename edge_list_type::iterator i = e.begin(); i != e.end(); ++i ) {
3233  remove_edge(**i, r);
3234  }
3235 }
3236 #endif /* TBB_DEPRECATED_FLOW_NODE_EXTRACTION */
3237 
3239 template< typename Body, typename Node >
3240 Body copy_body( Node &n ) {
3241  return n.template copy_function_object<Body>();
3242 }
3243 
3244 #if __TBB_FLOW_GRAPH_CPP11_FEATURES
3245 
3246 //composite_node
3247 template< typename InputTuple, typename OutputTuple > class composite_node;
3248 
3249 template< typename... InputTypes, typename... OutputTypes>
3250 class composite_node <tbb::flow::tuple<InputTypes...>, tbb::flow::tuple<OutputTypes...> > : public graph_node{
3251 
3252 public:
3253  typedef tbb::flow::tuple< receiver<InputTypes>&... > input_ports_type;
3254  typedef tbb::flow::tuple< sender<OutputTypes>&... > output_ports_type;
3255 
3256 private:
3257  std::unique_ptr<input_ports_type> my_input_ports;
3258  std::unique_ptr<output_ports_type> my_output_ports;
3259 
3260  static const size_t NUM_INPUTS = sizeof...(InputTypes);
3261  static const size_t NUM_OUTPUTS = sizeof...(OutputTypes);
3262 
3263 protected:
3265 
3266 public:
3267 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
3268  composite_node( graph &g, const char *type_name = "composite_node" ) : graph_node(g) {
3269  tbb::internal::fgt_multiinput_multioutput_node( tbb::internal::FLOW_COMPOSITE_NODE, this, &this->my_graph );
3271  }
3272 #else
3274  tbb::internal::fgt_multiinput_multioutput_node( tbb::internal::FLOW_COMPOSITE_NODE, this, &this->my_graph );
3275  }
3276 #endif
3277 
3278  template<typename T1, typename T2>
3279  void set_external_ports(T1&& input_ports_tuple, T2&& output_ports_tuple) {
3280  __TBB_STATIC_ASSERT(NUM_INPUTS == tbb::flow::tuple_size<input_ports_type>::value, "number of arguments does not match number of input ports");
3281  __TBB_STATIC_ASSERT(NUM_OUTPUTS == tbb::flow::tuple_size<output_ports_type>::value, "number of arguments does not match number of output ports");
3282  my_input_ports = tbb::internal::make_unique<input_ports_type>(std::forward<T1>(input_ports_tuple));
3283  my_output_ports = tbb::internal::make_unique<output_ports_type>(std::forward<T2>(output_ports_tuple));
3284 
3287  }
3288 
3289  template< typename... NodeTypes >
3290  void add_visible_nodes(const NodeTypes&... n) { internal::add_nodes_impl(this, true, n...); }
3291 
3292  template< typename... NodeTypes >
3293  void add_nodes(const NodeTypes&... n) { internal::add_nodes_impl(this, false, n...); }
3294 
3295 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
3296  void set_name( const char *name ) __TBB_override {
3298  }
3299 #endif
3300 
3302  __TBB_ASSERT(my_input_ports, "input ports not set, call set_external_ports to set input ports");
3303  return *my_input_ports;
3304  }
3305 
3307  __TBB_ASSERT(my_output_ports, "output ports not set, call set_external_ports to set output ports");
3308  return *my_output_ports;
3309  }
3310 
3311 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
3312  void extract() __TBB_override {
3313  __TBB_ASSERT(false, "Current composite_node implementation does not support extract");
3314  }
3315 #endif
3316 }; // class composite_node
3317 
3318 //composite_node with only input ports
3319 template< typename... InputTypes>
3320 class composite_node <tbb::flow::tuple<InputTypes...>, tbb::flow::tuple<> > : public graph_node {
3321 public:
3322  typedef tbb::flow::tuple< receiver<InputTypes>&... > input_ports_type;
3323 
3324 private:
3325  std::unique_ptr<input_ports_type> my_input_ports;
3326  static const size_t NUM_INPUTS = sizeof...(InputTypes);
3327 
3328 protected:
3330 
3331 public:
3332 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
3333  composite_node( graph &g, const char *type_name = "composite_node") : graph_node(g) {
3334  tbb::internal::fgt_composite( this, &g );
3336  }
3337 #else
3339  tbb::internal::fgt_composite( this, &g );
3340  }
3341 #endif
3342 
3343  template<typename T>
3344  void set_external_ports(T&& input_ports_tuple) {
3345  __TBB_STATIC_ASSERT(NUM_INPUTS == tbb::flow::tuple_size<input_ports_type>::value, "number of arguments does not match number of input ports");
3346 
3347  my_input_ports = tbb::internal::make_unique<input_ports_type>(std::forward<T>(input_ports_tuple));
3348 
3349  tbb::internal::fgt_internal_input_alias_helper<T, NUM_INPUTS>::alias_port( this, std::forward<T>(input_ports_tuple));
3350  }
3351 
3352  template< typename... NodeTypes >
3353  void add_visible_nodes(const NodeTypes&... n) { internal::add_nodes_impl(this, true, n...); }
3354 
3355  template< typename... NodeTypes >
3356  void add_nodes( const NodeTypes&... n) { internal::add_nodes_impl(this, false, n...); }
3357 
3358 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
3359  void set_name( const char *name ) __TBB_override {
3361  }
3362 #endif
3363 
3365  __TBB_ASSERT(my_input_ports, "input ports not set, call set_external_ports to set input ports");
3366  return *my_input_ports;
3367  }
3368 
3369 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
3370  void extract() __TBB_override {
3371  __TBB_ASSERT(false, "Current composite_node implementation does not support extract");
3372  }
3373 #endif
3374 
3375 }; // class composite_node
3376 
3377 //composite_nodes with only output_ports
3378 template<typename... OutputTypes>
3379 class composite_node <tbb::flow::tuple<>, tbb::flow::tuple<OutputTypes...> > : public graph_node {
3380 public:
3381  typedef tbb::flow::tuple< sender<OutputTypes>&... > output_ports_type;
3382 
3383 private:
3384  std::unique_ptr<output_ports_type> my_output_ports;
3385  static const size_t NUM_OUTPUTS = sizeof...(OutputTypes);
3386 
3387 protected:
3389 
3390 public:
3391 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
3392  composite_node( graph &g, const char *type_name = "composite_node") : graph_node(g) {
3393  tbb::internal::fgt_composite( this, &g );
3395  }
3396 #else
3398  tbb::internal::fgt_composite( this, &g );
3399  }
3400 #endif
3401 
3402  template<typename T>
3403  void set_external_ports(T&& output_ports_tuple) {
3404  __TBB_STATIC_ASSERT(NUM_OUTPUTS == tbb::flow::tuple_size<output_ports_type>::value, "number of arguments does not match number of output ports");
3405 
3406  my_output_ports = tbb::internal::make_unique<output_ports_type>(std::forward<T>(output_ports_tuple));
3407 
3408  tbb::internal::fgt_internal_output_alias_helper<T, NUM_OUTPUTS>::alias_port( this, std::forward<T>(output_ports_tuple));
3409  }
3410 
3411  template<typename... NodeTypes >
3412  void add_visible_nodes(const NodeTypes&... n) { internal::add_nodes_impl(this, true, n...); }
3413 
3414  template<typename... NodeTypes >
3415  void add_nodes(const NodeTypes&... n) { internal::add_nodes_impl(this, false, n...); }
3416 
3417 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
3418  void set_name( const char *name ) __TBB_override {
3420  }
3421 #endif
3422 
3424  __TBB_ASSERT(my_output_ports, "output ports not set, call set_external_ports to set output ports");
3425  return *my_output_ports;
3426  }
3427 
3428 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
3429  void extract() __TBB_override {
3430  __TBB_ASSERT(false, "Current composite_node implementation does not support extract");
3431  }
3432 #endif
3433 
3434 }; // class composite_node
3435 
3436 #endif // __TBB_FLOW_GRAPH_CPP11_FEATURES
3437 
3438 namespace internal {
3439 
3440 template<typename Gateway>
3442 public:
3443  typedef Gateway gateway_type;
3444 
3445  async_body_base(gateway_type *gateway): my_gateway(gateway) { }
3446  void set_gateway(gateway_type *gateway) {
3447  my_gateway = gateway;
3448  }
3449 
3450 protected:
3452 };
3453 
3454 template<typename Input, typename Ports, typename Gateway, typename Body>
3455 class async_body: public async_body_base<Gateway> {
3456 public:
3458  typedef Gateway gateway_type;
3459 
3460  async_body(const Body &body, gateway_type *gateway)
3461  : base_type(gateway), my_body(body) { }
3462 
3463  void operator()( const Input &v, Ports & ) {
3464  my_body(v, *this->my_gateway);
3465  }
3466 
3467  Body get_body() { return my_body; }
3468 
3469 private:
3470  Body my_body;
3471 };
3472 
3473 }
3474 
3476 template < typename Input, typename Output,
3477  typename Policy = queueing_lightweight,
3478  typename Allocator=cache_aligned_allocator<Input> >
3479 class async_node : public multifunction_node< Input, tuple< Output >, Policy, Allocator >, public sender< Output > {
3482 
3483 public:
3484  typedef Input input_type;
3485  typedef Output output_type;
3492 
3493 private:
3497  const Output *value;
3498  bool result;
3499  try_put_functor(output_port_type &p, const Output &v) : port(&p), value(&v), result(false) { }
3500  void operator()() {
3501  result = port->try_put(*value);
3502  }
3503  };
3504 
3505  class receiver_gateway_impl: public receiver_gateway<Output> {
3506  public:
3507  receiver_gateway_impl(async_node* node): my_node(node) {}
3509  tbb::internal::fgt_async_reserve(static_cast<typename async_node::receiver_type *>(my_node), &my_node->my_graph);
3510  my_node->my_graph.reserve_wait();
3511  }
3512 
3514  my_node->my_graph.release_wait();
3515  tbb::internal::fgt_async_commit(static_cast<typename async_node::receiver_type *>(my_node), &my_node->my_graph);
3516  }
3517 
3519  bool try_put(const Output &i) __TBB_override {
3520  return my_node->try_put_impl(i);
3521  }
3522 
3523  private:
3525  } my_gateway;
3526 
3527  //The substitute of 'this' for member construction, to prevent compiler warnings
3528  async_node* self() { return this; }
3529 
3531  bool try_put_impl(const Output &i) {
3532  internal::multifunction_output<Output> &port_0 = internal::output_port<0>(*this);
3534  try_put_functor tpf(port_0, i);
3535  internal::execute_in_graph_arena(this->my_graph, tpf);
3536  tbb::internal::fgt_async_try_put_end(this, &port_0);
3537  return tpf.result;
3538  }
3539 
3540 public:
3541  template<typename Body>
3542  async_node( graph &g, size_t concurrency, Body body ) :
3543  base_type( g, concurrency, internal::async_body<Input, typename base_type::output_ports_type, gateway_type, Body>(body, &my_gateway) ), my_gateway(self()) {
3544  tbb::internal::fgt_multioutput_node_with_body<1>( tbb::internal::FLOW_ASYNC_NODE,
3545  &this->my_graph, static_cast<receiver<input_type> *>(this),
3546  this->output_ports(), this->my_body );
3547  }
3548 
3549  async_node( const async_node &other ) : base_type(other), sender<Output>(), my_gateway(self()) {
3550  static_cast<async_body_base_type*>(this->my_body->get_body_ptr())->set_gateway(&my_gateway);
3551  static_cast<async_body_base_type*>(this->my_init_body->get_body_ptr())->set_gateway(&my_gateway);
3552 
3553  tbb::internal::fgt_multioutput_node_with_body<1>( tbb::internal::FLOW_ASYNC_NODE,
3554  &this->my_graph, static_cast<receiver<input_type> *>(this),
3555  this->output_ports(), this->my_body );
3556  }
3557 
3559  return my_gateway;
3560  }
3561 
3562 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
3563  void set_name( const char *name ) __TBB_override {
3565  }
3566 #endif
3567 
3568  // Define sender< Output >
3569 
3572  return internal::output_port<0>(*this).register_successor(r);
3573  }
3574 
3577  return internal::output_port<0>(*this).remove_successor(r);
3578  }
3579 
3580  template<typename Body>
3584  mfn_body_type &body_ref = *this->my_body;
3585  async_body_type ab = *static_cast<async_body_type*>(dynamic_cast< internal::multifunction_body_leaf<input_type, typename base_type::output_ports_type, async_body_type> & >(body_ref).get_body_ptr());
3586  return ab.get_body();
3587  }
3588 
3589 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
3590  typedef typename internal::edge_container<successor_type> built_successors_type;
3592  typedef typename built_successors_type::edge_list_type successor_list_type;
3593  built_successors_type &built_successors() __TBB_override {
3594  return internal::output_port<0>(*this).built_successors();
3595  }
3596 
3597  void internal_add_built_successor( successor_type &r ) __TBB_override {
3598  internal::output_port<0>(*this).internal_add_built_successor(r);
3599  }
3600 
3601  void internal_delete_built_successor( successor_type &r ) __TBB_override {
3602  internal::output_port<0>(*this).internal_delete_built_successor(r);
3603  }
3604 
3605  void copy_successors( successor_list_type &l ) __TBB_override {
3606  internal::output_port<0>(*this).copy_successors(l);
3607  }
3608 
3609  size_t successor_count() __TBB_override {
3610  return internal::output_port<0>(*this).successor_count();
3611  }
3612 #endif /* TBB_DEPRECATED_FLOW_NODE_EXTRACTION */
3613 
3614 protected:
3615 
3617  base_type::reset_node(f);
3618  }
3619 };
3620 
3621 #if __TBB_PREVIEW_STREAMING_NODE
3623 #endif // __TBB_PREVIEW_STREAMING_NODE
3624 
3625 } // interfaceX
3626 
3627 
3628 namespace interface10a {
3629 
3630 using namespace interface10;
3631 namespace internal = interface10::internal;
3632 
3633 template< typename T >
3634 class overwrite_node : public graph_node, public receiver<T>, public sender<T> {
3635 public:
3636  typedef T input_type;
3637  typedef T output_type;
3640 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
3641  typedef typename receiver<input_type>::built_predecessors_type built_predecessors_type;
3642  typedef typename sender<output_type>::built_successors_type built_successors_type;
3643  typedef typename receiver<input_type>::predecessor_list_type predecessor_list_type;
3644  typedef typename sender<output_type>::successor_list_type successor_list_type;
3645 #endif
3646 
3647  explicit overwrite_node(graph &g) : graph_node(g), my_buffer_is_valid(false) {
3648  my_successors.set_owner( this );
3649  tbb::internal::fgt_node( tbb::internal::FLOW_OVERWRITE_NODE, &this->my_graph,
3650  static_cast<receiver<input_type> *>(this), static_cast<sender<output_type> *>(this) );
3651  }
3652 
3655  graph_node(src.my_graph), receiver<T>(), sender<T>(), my_buffer_is_valid(false)
3656  {
3657  my_successors.set_owner( this );
3658  tbb::internal::fgt_node( tbb::internal::FLOW_OVERWRITE_NODE, &this->my_graph,
3659  static_cast<receiver<input_type> *>(this), static_cast<sender<output_type> *>(this) );
3660  }
3661 
3663 
3664 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
3665  void set_name( const char *name ) __TBB_override {
3667  }
3668 #endif
3669 
3671  spin_mutex::scoped_lock l( my_mutex );
3672  if (my_buffer_is_valid && internal::is_graph_active( my_graph )) {
3673  // We have a valid value that must be forwarded immediately.
3674  bool ret = s.try_put( my_buffer );
3675  if ( ret ) {
3676  // We add the successor that accepted our put
3677  my_successors.register_successor( s );
3678  } else {
3679  // In case of reservation a race between the moment of reservation and register_successor can appear,
3680  // because failed reserve does not mean that register_successor is not ready to put a message immediately.
3681  // We have some sort of infinite loop: reserving node tries to set pull state for the edge,
3682  // but overwrite_node tries to return push state back. That is why we have to break this loop with task creation.
3683  task *rtask = new ( task::allocate_additional_child_of( *( my_graph.root_task() ) ) )
3684  register_predecessor_task( *this, s );
3685  internal::spawn_in_graph_arena( my_graph, *rtask );
3686  }
3687  } else {
3688  // No valid value yet, just add as successor
3689  my_successors.register_successor( s );
3690  }
3691  return true;
3692  }
3693 
3695  spin_mutex::scoped_lock l( my_mutex );
3696  my_successors.remove_successor(s);
3697  return true;
3698  }
3699 
3700 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
3701  built_predecessors_type &built_predecessors() __TBB_override { return my_built_predecessors; }
3702  built_successors_type &built_successors() __TBB_override { return my_successors.built_successors(); }
3703 
3704  void internal_add_built_successor( successor_type &s) __TBB_override {
3705  spin_mutex::scoped_lock l( my_mutex );
3706  my_successors.internal_add_built_successor(s);
3707  }
3708 
3709  void internal_delete_built_successor( successor_type &s) __TBB_override {
3710  spin_mutex::scoped_lock l( my_mutex );
3711  my_successors.internal_delete_built_successor(s);
3712  }
3713 
3714  size_t successor_count() __TBB_override {
3715  spin_mutex::scoped_lock l( my_mutex );
3716  return my_successors.successor_count();
3717  }
3718 
3719  void copy_successors(successor_list_type &v) __TBB_override {
3720  spin_mutex::scoped_lock l( my_mutex );
3721  my_successors.copy_successors(v);
3722  }
3723 
3724  void internal_add_built_predecessor( predecessor_type &p) __TBB_override {
3725  spin_mutex::scoped_lock l( my_mutex );
3726  my_built_predecessors.add_edge(p);
3727  }
3728 
3729  void internal_delete_built_predecessor( predecessor_type &p) __TBB_override {
3730  spin_mutex::scoped_lock l( my_mutex );
3731  my_built_predecessors.delete_edge(p);
3732  }
3733 
3734  size_t predecessor_count() __TBB_override {
3735  spin_mutex::scoped_lock l( my_mutex );
3736  return my_built_predecessors.edge_count();
3737  }
3738 
3739  void copy_predecessors( predecessor_list_type &v ) __TBB_override {
3740  spin_mutex::scoped_lock l( my_mutex );
3741  my_built_predecessors.copy_edges(v);
3742  }
3743 
3744  void extract() __TBB_override {
3745  my_buffer_is_valid = false;
3746  built_successors().sender_extract(*this);
3747  built_predecessors().receiver_extract(*this);
3748  }
3749 
3750 #endif /* TBB_DEPRECATED_FLOW_NODE_EXTRACTION */
3751 
3753  spin_mutex::scoped_lock l( my_mutex );
3754  if ( my_buffer_is_valid ) {
3755  v = my_buffer;
3756  return true;
3757  }
3758  return false;
3759  }
3760 
3763  return try_get(v);
3764  }
3765 
3767  bool try_release() __TBB_override { return true; }
3768 
3770  bool try_consume() __TBB_override { return true; }
3771 
3772  bool is_valid() {
3773  spin_mutex::scoped_lock l( my_mutex );
3774  return my_buffer_is_valid;
3775  }
3776 
3777  void clear() {
3778  spin_mutex::scoped_lock l( my_mutex );
3779  my_buffer_is_valid = false;
3780  }
3781 
3782 protected:
3783 
3784  template< typename R, typename B > friend class run_and_put_task;
3785  template<typename X, typename Y> friend class internal::broadcast_cache;
3786  template<typename X, typename Y> friend class internal::round_robin_cache;
3789  return try_put_task_impl(v);
3790  }
3791 
3793  my_buffer = v;
3794  my_buffer_is_valid = true;
3795  task * rtask = my_successors.try_put_task(v);
3796  if (!rtask) rtask = SUCCESSFULLY_ENQUEUED;
3797  return rtask;
3798  }
3799 
3801  return my_graph;
3802  }
3803 
3807  o(owner), s(succ) {};
3808 
3810  if (!s.register_predecessor(o)) {
3811  o.register_successor(s);
3812  }
3813  return NULL;
3814  }
3815 
3818  };
3819 
3822 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
3823  internal::edge_container<predecessor_type> my_built_predecessors;
3824 #endif
3828 
3830  my_buffer_is_valid = false;
3831  if (f&rf_clear_edges) {
3832  my_successors.clear();
3833  }
3834  }
3835 }; // overwrite_node
3836 
3837 template< typename T >
3838 class write_once_node : public overwrite_node<T> {
3839 public:
3840  typedef T input_type;
3841  typedef T output_type;
3845 
3847  explicit write_once_node(graph& g) : base_type(g) {
3848  tbb::internal::fgt_node( tbb::internal::FLOW_WRITE_ONCE_NODE, &(this->my_graph),
3849  static_cast<receiver<input_type> *>(this),
3850  static_cast<sender<output_type> *>(this) );
3851  }
3852 
3855  tbb::internal::fgt_node( tbb::internal::FLOW_WRITE_ONCE_NODE, &(this->my_graph),
3856  static_cast<receiver<input_type> *>(this),
3857  static_cast<sender<output_type> *>(this) );
3858  }
3859 
3860 #if TBB_PREVIEW_FLOW_GRAPH_TRACE
3861  void set_name( const char *name ) __TBB_override {
3863  }
3864 #endif
3865 
3866 protected:
3867  template< typename R, typename B > friend class run_and_put_task;
3868  template<typename X, typename Y> friend class internal::broadcast_cache;
3869  template<typename X, typename Y> friend class internal::round_robin_cache;
3871  spin_mutex::scoped_lock l( this->my_mutex );
3872  return this->my_buffer_is_valid ? NULL : this->try_put_task_impl(v);
3873  }
3874 };
3875 } // interfaceX
3876 
3881 
3882  using interface10::graph;
3883  using interface10::graph_node;
3884  using interface10::continue_msg;
3885 
3886  using interface10::source_node;
3887  using interface10::function_node;
3888  using interface10::multifunction_node;
3889  using interface10::split_node;
3891  using interface10::indexer_node;
3892  using interface10::internal::tagged_msg;
3895  using interface10::continue_node;
3896  using interface10a::overwrite_node;
3897  using interface10a::write_once_node;
3898  using interface10::broadcast_node;
3899  using interface10::buffer_node;
3900  using interface10::queue_node;
3901  using interface10::sequencer_node;
3902  using interface10::priority_queue_node;
3903  using interface10::limiter_node;
3904  using namespace interface10::internal::graph_policy_namespace;
3905  using interface10::join_node;
3907  using interface10::copy_body;
3908  using interface10::make_edge;
3911 #if __TBB_FLOW_GRAPH_CPP11_FEATURES
3912  using interface10::composite_node;
3913 #endif
3914  using interface10::async_node;
3915 #if __TBB_PREVIEW_ASYNC_MSG
3916  using interface10::async_msg;
3917 #endif
3918 #if __TBB_PREVIEW_STREAMING_NODE
3919  using interface10::port_ref;
3920  using interface10::streaming_node;
3921 #endif // __TBB_PREVIEW_STREAMING_NODE
3922 
3923 } // flow
3924 } // tbb
3925 
3926 #undef __TBB_PFG_RESET_ARG
3927 #undef __TBB_COMMA
3928 
3929 #endif // __TBB_flow_graph_H
task * try_put_task(const T &v) __TBB_override
Put item to successor; return task to run the successor if possible.
Definition: flow_graph.h:3870
K key_from_message(const T &t)
Definition: flow_graph.h:691
internal::multifunction_input< input_type, output_ports_type, Policy, Allocator > input_impl_type
Definition: flow_graph.h:1209
internal::unfolded_indexer_node< InputTuple > unfolded_type
Definition: flow_graph.h:2962
internal::reservable_predecessor_cache< T, spin_mutex > my_predecessors
Definition: flow_graph.h:2408
limiter_node(const limiter_node &src)
Copy constructor.
Definition: flow_graph.h:2508
static tbb::task * combine_tasks(graph &g, tbb::task *left, tbb::task *right)
Definition: flow_graph.h:171
sender< output_type >::successor_type successor_type
Definition: flow_graph.h:2080
void set_ref_count(int count)
Set reference count.
Definition: task.h:718
untyped_sender predecessor_type
The predecessor type for this node.
Definition: flow_graph.h:343
split_node: accepts a tuple as input, forwards each element of the tuple to its
Definition: flow_graph.h:1250
static task * try_put_task_wrapper_impl(receiver< T > *const this_recv, const void *p, bool is_async)
Definition: flow_graph.h:217
internal::unfolded_indexer_node< InputTuple > unfolded_type
Definition: flow_graph.h:2861
graph & graph_reference() __TBB_override
Definition: flow_graph.h:1510
join_node(graph &g, __TBB_B0 b0, __TBB_B1 b1, __TBB_B2 b2, __TBB_B3 b3, __TBB_B4 b4, __TBB_B5 b5, __TBB_B6 b6, __TBB_B7 b7)
Definition: flow_graph.h:2783
bool remove_successor(successor_type &s) __TBB_override
Removes a successor from this node.
Definition: flow_graph.h:3694
void remove_edge(sender< T > &p, receiver< T > &s)
Removes an edge between a single predecessor and a single successor.
Definition: flow_graph.h:3173
graph()
Constructs a graph with isolated task_group_context.
Definition: flow_graph.h:741
graph & graph_reference() __TBB_override
Definition: flow_graph.h:2643
internal::round_robin_cache< T, null_rw_mutex > my_successors
Definition: flow_graph.h:1542
tbb::flow::tuple_element< N, typename JNT::input_ports_type >::type & input_port(JNT &jn)
templated function to refer to input ports of the join node
static void fgt_async_reserve(void *, void *)
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_id __itt_string_handle __itt_metadata_type size_t void ITT_FORMAT p const __itt_domain __itt_id __itt_string_handle const wchar_t size_t ITT_FORMAT lu const __itt_domain __itt_id __itt_relation __itt_id ITT_FORMAT p const wchar_t int ITT_FORMAT __itt_group_mark S
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_id __itt_string_handle __itt_metadata_type type
virtual bool try_consume()
Consumes the reserved item.
Definition: flow_graph.h:301
async_node(const async_node &other)
Definition: flow_graph.h:3549
priority_queue_node(const priority_queue_node &src)
Copy constructor.
Definition: flow_graph.h:2193
void reserve_wait() __TBB_override
Inform a graph that messages may come from outside, to prevent premature graph completion.
Definition: flow_graph.h:3508
void spawn_in_graph_arena(graph &g, tbb::task &arena_task)
Spawns a task inside graph arena.
bool remove_predecessor(predecessor_type &src) __TBB_override
Removes src from the list of cached predecessors.
Definition: flow_graph.h:2605
base_type::buffer_operation queue_operation
Definition: flow_graph.h:2028
void reserve_wait() __TBB_override
Used to register that an external entity may still interact with the graph.
Definition: flow_graph.h:771
static void fgt_async_commit(void *, void *)
sender< output_type >::successor_type successor_type
Definition: flow_graph.h:1534
const V & cast_to(T const &t)
Definition: flow_graph.h:705
internal::broadcast_cache< input_type > my_successors
Definition: flow_graph.h:1408
receiver_gateway< output_type > gateway_type
Definition: flow_graph.h:3489
Base class for user-defined tasks.
Definition: task.h:576
try_put_functor(output_port_type &p, const Output &v)
Definition: flow_graph.h:3499
receiver< input_type >::predecessor_type predecessor_type
Definition: flow_graph.h:2117
internal::tagged_msg< size_t, T0, T1, T2, T3, T4, T5, T6, T7, T8 > output_type
Definition: flow_graph.h:3045
internal::continue_input< Output, Policy > input_impl_type
Definition: flow_graph.h:1335
A generic null type.
Definition: flow_graph.h:93
internal::source_body< output_type > * my_body
Definition: flow_graph.h:1054
receiver< input_type >::predecessor_type predecessor_type
Definition: flow_graph.h:2394
bool register_successor(successor_type &r) __TBB_override
Add a new successor to this node.
Definition: flow_graph.h:3571
write_once_node(const write_once_node &src)
Copy constructor: call base class copy constructor.
Definition: flow_graph.h:3854
task * try_put_task(const T &t) __TBB_override
Puts an item to this receiver.
Definition: flow_graph.h:2616
void __TBB_store_with_release(volatile T &location, V value)
Definition: tbb_machine.h:717
internal::tagged_msg< size_t, T0 > output_type
Definition: flow_graph.h:2835
Forwards messages in FIFO order.
Definition: flow_graph.h:2024
A cache of predecessors that only supports try_get.
Definition: flow_graph.h:110
friend class scoped_lock
Definition: spin_mutex.h:180
void const char const char int ITT_FORMAT __itt_group_sync s
graph & graph_reference() __TBB_override
Definition: flow_graph.h:1994
interface10::internal::Policy< queueing, lightweight > queueing_lightweight
Definition: flow_graph.h:92
join_node(graph &g, __TBB_B0 b0, __TBB_B1 b1, __TBB_B2 b2)
Definition: flow_graph.h:2747
internal::unfolded_indexer_node< InputTuple > unfolded_type
Definition: flow_graph.h:3046
sender< output_type >::successor_type successor_type
Definition: flow_graph.h:2183
void internal_pop(prio_operation *op) __TBB_override
Definition: flow_graph.h:2231
void reset_receiver(reset_flags) __TBB_override
put receiver back in initial state
Definition: flow_graph.h:2647
join_node(graph &g, __TBB_B0 b0, __TBB_B1 b1, __TBB_B2 b2, __TBB_B3 b3, __TBB_B4 b4, __TBB_B5 b5, __TBB_B6 b6, __TBB_B7 b7, __TBB_B8 b8, __TBB_B9 b9)
Definition: flow_graph.h:2801
internal::function_output< output_type > fOutput_type
Definition: flow_graph.h:1124
bool try_release() __TBB_override
Releases the reserved item.
Definition: flow_graph.h:3767
receiver< input_type >::predecessor_type predecessor_type
The predecessor type for this node.
Definition: flow_graph.h:580
overwrite_node(const overwrite_node &src)
Copy constructor; doesn't take anything from src; default won't work.
Definition: flow_graph.h:3654
internal::async_helpers< T >::filtered_type filtered_type
Definition: flow_graph.h:403
internal::multifunction_input< Input, typename base_type::output_ports_type, Policy, Allocator > mfn_input_type
Definition: flow_graph.h:3481
static const T & from_void_ptr(const void *p)
Definition: flow_graph.h:209
sender< output_type >::successor_type successor_type
Definition: flow_graph.h:1402
Detects whether two given types are the same.
A lock that occupies a single byte.
Definition: spin_mutex.h:40
static void fgt_end_body(void *)
Output output_type
The type of the output message, which is complete.
Definition: flow_graph.h:864
virtual bool try_get(T &)
Request an item from the sender.
Definition: flow_graph.h:406
static void fgt_make_edge(void *, void *)
bool remove_successor(successor_type &r) __TBB_override
Removes a successor from this node.
Definition: flow_graph.h:921
internal::unfolded_indexer_node< InputTuple > unfolded_type
Definition: flow_graph.h:3074
bool try_consume() __TBB_override
Consumes the reserved item.
Definition: flow_graph.h:3770
void internal_remove_edge(internal::untyped_sender &p, internal::untyped_receiver &s)
Definition: flow_graph.h:3157
virtual bool try_release()
Releases the reserved item.
Definition: flow_graph.h:298
internal::async_body_base< gateway_type > async_body_base_type
Definition: flow_graph.h:3490
receiver< input_type >::predecessor_type predecessor_type
Definition: flow_graph.h:1533
virtual bool register_predecessor(predecessor_type &)
Add a predecessor to the node.
Definition: flow_graph.h:362
Meets "allocator" requirements of ISO C++ Standard, Section 20.1.5.
tbb::task_group_context * my_context
output_ports_type & output_ports()
Definition: flow_graph.h:1286
bool remove_successor(successor_type &r) __TBB_override
Removes a successor from this node.
Definition: flow_graph.h:2546
void register_node(graph_node *n)
Definition: flow_graph.h:785
void increment_ref_count()
Atomically increment reference count.
Definition: task.h:728
reference operator *() const
Dereference.
Definition: flow_graph.h:725
Base class for receivers of completion messages.
Definition: flow_graph.h:573
internal::decrementer< limiter_node< T > > decrement
The internal receiver< continue_msg > that decrements the count.
Definition: flow_graph.h:2491
void try_put_and_add_task(task *&last_task)
Definition: flow_graph.h:2038
An executable node that acts as a source, i.e. it has no predecessors.
Definition: flow_graph.h:861
Input and scheduling for a function node that takes a type Input as input.
Definition: flow_graph.h:65
virtual task * try_put_task(const T &t)=0
Put item to successor; return task to run the successor if possible.
receiver< input_type >::predecessor_type predecessor_type
Definition: flow_graph.h:2182
internal::unfolded_indexer_node< InputTuple > unfolded_type
Definition: flow_graph.h:2911
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 parent
bool try_consume() __TBB_override
Consumes a reserved item.
Definition: flow_graph.h:997
limiter_node(graph &g, size_t threshold, int num_decrement_predecessors=0)
Constructor.
Definition: flow_graph.h:2494
Implements methods for an executable node that takes continue_msg as input.
Definition: flow_graph.h:678
virtual task * forward_task()
This is executed by an enqueued task, the "forwarder".
Definition: flow_graph.h:1662
iterator begin()
start iterator
Definition: flow_graph.h:831
leaf for multifunction. OutputSet can be a std::tuple or a vector.
Definition: flow_graph.h:207
Implements methods for a function node that takes a type Input as input.
Definition: flow_graph.h:563
bool try_release() __TBB_override
Release a reserved item.
Definition: flow_graph.h:987
input_impl_type::predecessor_type predecessor_type
Definition: flow_graph.h:1337
void __TBB_EXPORTED_METHOD reset()
Forcefully reinitializes the context after the task tree it was associated with is completed.
virtual void internal_release(buffer_operation *op)
Definition: flow_graph.h:1818
A cache of successors that are put in a round-robin fashion.
Definition: flow_graph.h:109
void internal_pop(queue_operation *op) __TBB_override
Definition: flow_graph.h:2053
#define __TBB_ASSERT(predicate, comment)
No-op version of __TBB_ASSERT.
Definition: tbb_stddef.h:169
Implements methods for a function node that takes a type Input as input and sends.
Definition: flow_graph.h:421
receiver< input_type >::predecessor_type predecessor_type
Definition: flow_graph.h:3638
The base of all graph nodes.
#define __TBB_override
Definition: tbb_stddef.h:244
void const char const char int ITT_FORMAT __itt_group_sync p
internal::broadcast_cache< input_type, null_rw_mutex > my_successors
Definition: flow_graph.h:3821
internal::tagged_msg< size_t, T0, T1 > output_type
Definition: flow_graph.h:2860
internal::tagged_msg< size_t, T0, T1, T2, T3, T4, T5, T6 > output_type
Definition: flow_graph.h:2989
buffer_node< T, A >::size_type size_type
Definition: flow_graph.h:2147
internal::tagged_msg< size_t, T0, T1, T2, T3, T4, T5, T6, T7 > output_type
Definition: flow_graph.h:3017
sender< output_type >::successor_type successor_type
Definition: flow_graph.h:3488
Forwards messages of type T to all successors.
Definition: flow_graph.h:1397
void reset_receiver(reset_flags) __TBB_override
put receiver back in initial state
Definition: flow_graph.h:3827
join_node(graph &g, __TBB_B0 b0, __TBB_B1 b1, __TBB_B2 b2, __TBB_B3 b3)
Definition: flow_graph.h:2752
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
internal::function_input_queue< input_type, Allocator > input_queue_type
Definition: flow_graph.h:1210
input_impl_type::predecessor_type predecessor_type
Definition: flow_graph.h:1125
virtual void internal_reserve(buffer_operation *op)
Definition: flow_graph.h:1804
Base class for types that should not be assigned.
Definition: tbb_stddef.h:324
bool register_successor(successor_type &r) __TBB_override
Replace the current successor with this new successor.
Definition: flow_graph.h:2529
implements a function node that supports Input -> (set of outputs)
Definition: flow_graph.h:1190
virtual void internal_pop(buffer_operation *op)
Definition: flow_graph.h:1795
void reset_node(reset_flags f) __TBB_override
Definition: flow_graph.h:2651
tbb::flow::tuple_element< N, typename MOP::output_ports_type >::type & output_port(MOP &op)
Definition: flow_graph.h:644
void internal_release(prio_operation *op) __TBB_override
Definition: flow_graph.h:2263
void reset_node(reset_flags f) __TBB_override
Definition: flow_graph.h:1174
base_type::size_type size_type
Definition: flow_graph.h:2027
A task that calls a node's forward_task function.
Definition: flow_graph.h:275
function_node(graph &g, size_t concurrency, Body body)
Constructor.
Definition: flow_graph.h:1138
void execute_in_graph_arena(graph &g, F &f)
Executes custom functor inside graph arena.
bool try_reserve(T &v) __TBB_override
Reserves an item.
Definition: flow_graph.h:1943
fOutput_type::successor_type successor_type
Definition: flow_graph.h:1126
buffer_node< T, A >::buffer_operation sequencer_operation
Definition: flow_graph.h:2148
source_node(graph &g, Body body, bool is_active=true)
Constructor for a node with a successor.
Definition: flow_graph.h:879
bool internal_push(prio_operation *op) __TBB_override
Definition: flow_graph.h:2225
void make_edge(sender< T > &p, receiver< T > &s)
Makes an edge between a single predecessor and a single successor.
Definition: flow_graph.h:3109
internal::multifunction_output< Output > output_port_type
Definition: flow_graph.h:3495
virtual bool internal_push(buffer_operation *op)
Definition: flow_graph.h:1789
graph_iterator< graph, graph_node > iterator
untyped_receiver successor_type
The successor type for this node.
Definition: flow_graph.h:283
bool try_put(const typename internal::async_helpers< T >::filtered_type &t)
Put an item to the receiver.
Definition: flow_graph.h:445
indexer_node(const indexer_node &other)
Definition: flow_graph.h:3080
void reset_node(reset_flags f) __TBB_override
Definition: flow_graph.h:2009
internal::unfolded_indexer_node< InputTuple > unfolded_type
Definition: flow_graph.h:2886
Forward declaration section.
Definition: flow_graph.h:99
internal::wrap_tuple_elements< N, internal::multifunction_output, Output >::type output_ports_type
Definition: flow_graph.h:1208
bool try_reserve(X &t)
Reserves an item in the sender.
Definition: flow_graph.h:322
internal::multifunction_input< input_type, output_ports_type, Policy, Allocator > base_type
Definition: flow_graph.h:1212
sender< output_type >::successor_type successor_type
Definition: flow_graph.h:3844
Forwards messages in priority order.
Definition: flow_graph.h:2176
bool register_successor(successor_type &s) __TBB_override
Add a new successor to this node.
Definition: flow_graph.h:3670
graph & graph_reference() __TBB_override
Definition: flow_graph.h:1301
bool try_get(X &t)
Request an item from the sender.
Definition: flow_graph.h:316
receiver< input_type >::predecessor_type predecessor_type
Definition: flow_graph.h:1401
join_node(graph &g, __TBB_B0 b0, __TBB_B1 b1, __TBB_B2 b2, __TBB_B3 b3, __TBB_B4 b4, __TBB_B5 b5)
Definition: flow_graph.h:2765
sender< output_type >::successor_type successor_type
The type of successors of this node.
Definition: flow_graph.h:867
void remove_node(graph_node *n)
Definition: flow_graph.h:796
Represents acquisition of a mutex.
Definition: spin_mutex.h:54
static void fgt_multioutput_node_desc(const NodeType *, const char *)
internal::unfolded_indexer_node< InputTuple > unfolded_type
Definition: flow_graph.h:2936
continue_receiver(int number_of_predecessors=0)
Constructor.
Definition: flow_graph.h:583
internal::aggregating_functor< class_type, join_node_base_operation > handler_type
Definition: flow_graph.h:1311
internal::aggregating_functor< class_type, buffer_operation > handler_type
Definition: flow_graph.h:1590
Implements an executable node that supports continue_msg -> Output.
Definition: flow_graph.h:1330
static void fgt_reserve_wait(void *)
function_node(const function_node &src)
Copy constructor.
Definition: flow_graph.h:1145
const_iterator cend() const
end const iterator
Definition: flow_graph.h:841
virtual bool try_reserve(T &)
Reserves an item in the sender.
Definition: flow_graph.h:409
receiver< input_type > receiver_type
Definition: flow_graph.h:3486
internal::unfolded_join_node< N, key_matching_port, OutputTuple, key_matching< K, KHash > > unfolded_type
Definition: flow_graph.h:2732
A task that calls a node's apply_body_bypass function with no input.
Definition: flow_graph.h:311
Body copy_body(Node &n)
Returns a copy of the body from a function or continue node.
Definition: flow_graph.h:3240
bool try_reserve_apply_body(output_type &v)
Definition: flow_graph.h:1062
receiver_type::predecessor_type predecessor_type
Definition: flow_graph.h:3487
bool enqueue_forwarding_task(buffer_operation &op_data)
Definition: flow_graph.h:1652
register_predecessor_task(predecessor_type &owner, successor_type &succ)
Definition: flow_graph.h:3806
void internal_forward_task(queue_operation *op) __TBB_override
Tries to forward valid items to successors.
Definition: flow_graph.h:2049
Used to form groups of tasks.
Definition: task.h:319
internal::broadcast_cache< output_type > & successors() __TBB_override
Definition: flow_graph.h:1172
continue_node(graph &g, int number_of_predecessors, Body body)
Constructor for executable node with continue_msg -> Output.
Definition: flow_graph.h:1352
Implements a function node that supports Input -> Output.
Definition: flow_graph.h:1118
internal::aggregator< handler_type, buffer_operation > my_aggregator
Definition: flow_graph.h:1592
internal::unfolded_indexer_node< InputTuple > unfolded_type
Definition: flow_graph.h:2990
static void fgt_graph(void *)
sequencer_node(const sequencer_node &src)
Copy constructor.
Definition: flow_graph.h:2130
static void fgt_async_try_put_end(void *, void *)
virtual task * execute()=0
Does whatever should happen when the threshold is reached.
internal::unfolded_join_node< N, reserving_port, OutputTuple, reserving > unfolded_type
Definition: flow_graph.h:2679
void wait_for_all()
Wait until graph is idle and decrement_wait_count calls equals increment_wait_count calls.
static void fgt_composite(void *, void *)
A cache of successors that are broadcast to.
Definition: flow_graph.h:108
bool try_release() __TBB_override
Release a reserved item.
Definition: flow_graph.h:1953
static void fgt_node(string_index, void *, void *)
void reset_receiver(reset_flags) __TBB_override
put receiver back in initial state
Definition: flow_graph.h:1998
void internal_consume(prio_operation *op) __TBB_override
Definition: flow_graph.h:2257
Forwards messages only if the threshold has not been reached.
Definition: flow_graph.h:102
void internal_forward_task(prio_operation *op) __TBB_override
Tries to forward valid items to successors.
Definition: flow_graph.h:2217
void internal_reserve(prio_operation *op) __TBB_override
Definition: flow_graph.h:2245
virtual void reset_node(reset_flags f=rf_reset_protocol)=0
queue_node(graph &g)
Constructor.
Definition: flow_graph.h:2083
sender< output_type >::successor_type successor_type
Definition: flow_graph.h:3639
tbb::internal::uint64_t tag_value
Definition: flow_graph.h:33
virtual bool try_reserve_wrapper(void *p, bool is_async)=0
unfolded_join_node : passes input_ports_type to join_node_base. We build the input port type
Definition: flow_graph.h:1509
An empty class used for messages that mean "I'm done".
Definition: flow_graph.h:96
graph_iterator< const graph, const graph_node > const_iterator
virtual task * try_put_task_wrapper(const void *p, bool is_async)=0
Forwards messages in sequence order.
Definition: flow_graph.h:2110
multifunction_node< Input, tuple< Output >, Policy, Allocator > base_type
Definition: flow_graph.h:3480
buffer_node< T, A >::item_type item_type
Definition: flow_graph.h:2213
bool try_put_impl(const Output &i)
Implements gateway_type::try_put for an external activity to submit a message to FG.
Definition: flow_graph.h:3531
void try_put_and_add_task(task *&last_task)
Definition: flow_graph.h:2282
Forwards messages in arbitrary order.
Definition: flow_graph.h:1529
virtual bool try_reserve_wrapper(void *p, bool is_async) __TBB_override
Definition: flow_graph.h:422
Breaks an infinite loop between the node reservation and register_successor call.
Definition: flow_graph.h:3805
virtual bool try_get_wrapper(void *p, bool is_async) __TBB_override
Definition: flow_graph.h:412
bool try_consume() __TBB_override
Consumes a reserved item.
Definition: flow_graph.h:1962
buffer_node< T, A >::buffer_operation prio_operation
Definition: flow_graph.h:2214
fOutput_type::successor_type successor_type
Definition: flow_graph.h:1338
bool try_put(const X &t)
Put an item to the receiver.
Definition: flow_graph.h:350
bool register_successor(successor_type &r) __TBB_override
Adds a new successor.
Definition: flow_graph.h:1855
virtual bool try_get_wrapper(void *p, bool is_async)=0
internal::tagged_msg< size_t, T0, T1, T2, T3 > output_type
Definition: flow_graph.h:2910
buffer_node< T, A >::size_type size_type
Definition: flow_graph.h:2212
void reset_receiver(reset_flags f) __TBB_override
put receiver back in initial state
Definition: flow_graph.h:668
void reset_node(reset_flags f) __TBB_override
Definition: flow_graph.h:3829
void internal_reserve(queue_operation *op) __TBB_override
Definition: flow_graph.h:2062
continue_node(const continue_node &src)
Copy constructor.
Definition: flow_graph.h:1360
void internal_consume(queue_operation *op) __TBB_override
Definition: flow_graph.h:2071
static void fgt_node_with_body(string_index, void *, void *, void *)
An abstract cache of successors.
Definition: flow_graph.h:107
bool try_reserve(output_type &v) __TBB_override
Reserves an item.
Definition: flow_graph.h:970
static void fgt_node_desc(const NodeType *, const char *)
void release_wait() __TBB_override
Deregisters an external entity that may have interacted with the graph.
Definition: flow_graph.h:778
internal::tagged_msg< size_t, T0, T1, T2, T3, T4, T5 > output_type
Definition: flow_graph.h:2961
internal::function_output< output_type > fOutput_type
Definition: flow_graph.h:1336
virtual void finalize() const
Definition: flow_graph.h:151
Pure virtual template class that defines a receiver of messages of type T.
Definition: flow_graph.h:100
multifunction_node(graph &g, size_t concurrency, Body body)
Definition: flow_graph.h:1216
The graph class.
item_buffer with reservable front-end. NOTE: if reserving, do not
Definition: flow_graph.h:253
Implements async node.
Definition: flow_graph.h:3479
static void fgt_release_wait(void *)
receiver< input_type >::predecessor_type predecessor_type
Definition: flow_graph.h:3843
pointer operator->() const
Dereference.
Definition: flow_graph.h:731
indexer_node(const indexer_node &other)
Definition: flow_graph.h:2842
graph & graph_reference() __TBB_override
Definition: flow_graph.h:3800
bool try_get(output_type &v) __TBB_override
Request an item from the node.
Definition: flow_graph.h:953
join_node(graph &g, __TBB_B0 b0, __TBB_B1 b1, __TBB_B2 b2, __TBB_B3 b3, __TBB_B4 b4, __TBB_B5 b5, __TBB_B6 b6)
Definition: flow_graph.h:2774
sequencer_node(graph &g, const Sequencer &s)
Constructor.
Definition: flow_graph.h:2122
void reset_node(reset_flags f) __TBB_override
Definition: flow_graph.h:1388
void release_wait() __TBB_override
Inform a graph that a previous call to reserve_wait is no longer in effect.
Definition: flow_graph.h:3513
void spawn_put()
Spawns a task that applies the body.
Definition: flow_graph.h:1094
wrap_tuple_elements< N, PT, OutputTuple >::type input_ports_type
Definition: flow_graph.h:1511
static void fgt_async_try_put_begin(void *, void *)
static void fgt_remove_edge(void *, void *)
sender< output_type >::successor_type successor_type
Definition: flow_graph.h:2118
join_node(graph &g, __TBB_B0 b0, __TBB_B1 b1, __TBB_B2 b2, __TBB_B3 b3, __TBB_B4 b4, __TBB_B5 b5, __TBB_B6 b6, __TBB_B7 b7, __TBB_B8 b8)
Definition: flow_graph.h:2792
buffer_node(const buffer_node &src)
Copy constructor.
Definition: flow_graph.h:1834
internal::unfolded_indexer_node< InputTuple > unfolded_type
Definition: flow_graph.h:2836
virtual bool register_successor(successor_type &r)=0
Add a new successor to this node.
internal::return_type_or_void< F >::type execute(F &f)
Definition: task_arena.h:332
virtual void internal_reg_succ(buffer_operation *op)
Register successor.
Definition: flow_graph.h:1679
static void fgt_graph_desc(void *, const char *)
internal::broadcast_cache< T > my_successors
Definition: flow_graph.h:2410
void try_put_and_add_task(task *&last_task)
Definition: flow_graph.h:1748
receiver< TupleType > base_type
Definition: flow_graph.h:1252
tbb::task * execute() __TBB_override
Should be overridden by derived classes.
Definition: flow_graph.h:3809
continue_node(graph &g, Body body)
Constructor for executable node with continue_msg -> Output.
Definition: flow_graph.h:1342
void internal_make_edge(internal::untyped_sender &p, internal::untyped_receiver &s)
Definition: flow_graph.h:3094
continue_msg input_type
The input type.
Definition: flow_graph.h:577
internal::async_helpers< T >::filtered_type filtered_type
Definition: flow_graph.h:442
void reset_node(reset_flags f) __TBB_override
Definition: flow_graph.h:2207
virtual void reset_receiver(reset_flags f=rf_reset_protocol)=0
put receiver back in initial state
bool register_successor(successor_type &r) __TBB_override
Add a new successor to this node.
Definition: flow_graph.h:912
iterator end()
end iterator
Definition: flow_graph.h:833
continue_receiver(const continue_receiver &src)
Copy constructor.
Definition: flow_graph.h:589
void add_task_to_graph_reset_list(graph &g, tbb::task *tp)
task * try_put_task(const input_type &) __TBB_override
Put item to successor; return task to run the successor if possible.
Definition: flow_graph.h:643
void fgt_multiinput_multioutput_node_desc(const NodeType *, const char *)
bool try_put(const Output &i) __TBB_override
Implements gateway_type::try_put for an external activity to submit a message to FG.
Definition: flow_graph.h:3519
task * apply_body_bypass()
Applies the body. Returning SUCCESSFULLY_ENQUEUED okay; forward_task_bypass will handle it.
Definition: flow_graph.h:1102
T input_type
The input type of this receiver.
Definition: flow_graph.h:440
tbb::flow::tuple_element< N, typename JNT::input_ports_type >::type & input_port(JNT &jn)
templated function to refer to input ports of the join node
Definition: flow_graph.h:1997
static internal::allocate_root_proxy allocate_root()
Returns proxy for overloaded new that allocates a root task.
Definition: task.h:620
void add_nodes_impl(CompositeType *, bool)
Definition: flow_graph.h:874
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
receiver< input_type >::predecessor_type predecessor_type
Definition: flow_graph.h:2079
bool remove_successor(successor_type &r) __TBB_override
Removes s as a successor.
Definition: flow_graph.h:1443
bool register_predecessor(predecessor_type &src) __TBB_override
Adds src to the list of cached predecessors.
Definition: flow_graph.h:2593
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 begin
void reset(reset_flags f=rf_reset_protocol)
Definition: flow_graph.h:808
int decrement_ref_count()
Atomically decrement reference count and returns its new value.
Definition: task.h:745
static void fgt_begin_body(void *)
const_iterator cbegin() const
start const iterator
Definition: flow_graph.h:839
virtual bool remove_predecessor(predecessor_type &)
Remove a predecessor from the node.
Definition: flow_graph.h:365
task * try_put_task(const input_type &v) __TBB_override
Put item to successor; return task to run the successor if possible.
Definition: flow_graph.h:3787
bool try_get(input_type &v) __TBB_override
Request an item from the sender.
Definition: flow_graph.h:3752
internal::broadcast_cache< output_type > & successors() __TBB_override
Definition: flow_graph.h:1386
task that does nothing. Useful for synchronization.
Definition: task.h:927
void internal_forward_task_impl(buffer_operation *op, derived_type *derived)
Definition: flow_graph.h:1765
void reset_node(reset_flags f) __TBB_override
resets the source_node to its initial state
Definition: flow_graph.h:1034
sender< output_type >::successor_type successor_type
Definition: flow_graph.h:2395
async_body_base< Gateway > base_type
Definition: flow_graph.h:3457
graph & graph_reference() __TBB_override
virtual void internal_rem_succ(buffer_operation *op)
Remove successor.
Definition: flow_graph.h:1685
split_node(const split_node &other)
Definition: flow_graph.h:1274
queue_node(const queue_node &src)
Copy constructor.
Definition: flow_graph.h:2090
function_body that takes an Input and a set of output ports
Definition: flow_graph.h:197
tuple< T0, T1, T2, T3, T4, T5, T6, T7, T8, T9 > InputTuple
Definition: flow_graph.h:3072
virtual task * execute()=0
Should be overridden by derived classes.
An cache of predecessors that supports requests and reservations.
Definition: flow_graph.h:111
void reset_node(reset_flags f) __TBB_override
Definition: flow_graph.h:2103
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 * lock
void operator()(const Input &v, Ports &)
Definition: flow_graph.h:3463
task * try_put_task(const T &t) __TBB_override
build a task to run the successor if possible. Default is old behavior.
Definition: flow_graph.h:1504
internal::unfolded_indexer_node< InputTuple > unfolded_type
Definition: flow_graph.h:3018
broadcast_node(const broadcast_node &src)
Definition: flow_graph.h:1422
void reset_node(reset_flags f) __TBB_override
Definition: flow_graph.h:3616
virtual void handle_operations(buffer_operation *op_list)
Definition: flow_graph.h:1594
bool internal_push(sequencer_operation *op) __TBB_override
Definition: flow_graph.h:2151
task * try_put_task_impl(const input_type &v)
Definition: flow_graph.h:3792
~graph()
Destroys the graph.
Definition: flow_graph.h:763
internal::function_input< input_type, output_type, Policy, Allocator > input_impl_type
Definition: flow_graph.h:1122
static void fgt_multiinput_multioutput_node(string_index, void *, void *)
source_node(const source_node &src)
Copy constructor.
Definition: flow_graph.h:891
async_body(const Body &body, gateway_type *gateway)
Definition: flow_graph.h:3460
async_node(graph &g, size_t concurrency, Body body)
Definition: flow_graph.h:3542
internal::port_ref_impl< N1, N2 > port_ref()
Definition: flow_graph.h:46
bool remove_successor(successor_type &r) __TBB_override
Removes a successor.
Definition: flow_graph.h:1917
internal::tagged_msg< size_t, T0, T1, T2, T3, T4 > output_type
Definition: flow_graph.h:2935
void const char const char int ITT_FORMAT __itt_group_sync x void const char * name
internal::function_input_queue< input_type, Allocator > input_queue_type
Definition: flow_graph.h:1123
static tbb::task *const SUCCESSFULLY_ENQUEUED
internal::unfolded_join_node< N, queueing_port, OutputTuple, queueing > unfolded_type
Definition: flow_graph.h:2704
static const void * to_void_ptr(const T &t)
Definition: flow_graph.h:201
bool is_continue_receiver() __TBB_override
Definition: flow_graph.h:683
internal::tagged_msg< size_t, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9 > output_type
Definition: flow_graph.h:3073
void handle_operations(prio_operation *op_list) __TBB_override
Definition: flow_graph.h:2221
task * try_put_task(const T &t) __TBB_override
receive an item, return a task *if possible
Definition: flow_graph.h:1975
base_type::output_ports_type output_ports_type
Definition: flow_graph.h:3491
void prepare_task_arena(bool reinit=false)
Implements methods for both executable and function nodes that puts Output to its successors.
Definition: flow_graph.h:774
void reset_receiver(reset_flags) __TBB_override
put receiver back in initial state
Definition: flow_graph.h:1300
bool try_reserve(T &v) __TBB_override
Reserves an item.
Definition: flow_graph.h:3762
void reset_receiver(reset_flags) __TBB_override
put receiver back in initial state
Definition: flow_graph.h:1514
bool register_predecessor(predecessor_type &) __TBB_override
Increments the trigger threshold.
Definition: flow_graph.h:595
static task * emit_this(graph &g, const T &t, P &p)
Definition: flow_graph.h:658
virtual bool remove_successor(successor_type &r)=0
Removes a successor from this node.
bool register_successor(successor_type &r) __TBB_override
Adds a successor.
Definition: flow_graph.h:1437
T output_type
The output type of this sender.
Definition: flow_graph.h:401
internal::function_body< T, size_t > * my_sequencer
Definition: flow_graph.h:2111
Enables one or the other code branches.
virtual task * try_put_task_wrapper(const void *p, bool is_async) __TBB_override
Definition: flow_graph.h:454
internal::wrap_tuple_elements< N, internal::multifunction_output, TupleType >::type output_ports_type
Definition: flow_graph.h:1267
internal::tagged_msg< size_t, T0, T1, T2 > output_type
Definition: flow_graph.h:2885
#define __TBB_STATIC_ASSERT(condition, msg)
Definition: tbb_stddef.h:545
join_node(graph &g, __TBB_B0 b0, __TBB_B1 b1, __TBB_B2 b2, __TBB_B3 b3, __TBB_B4 b4)
Definition: flow_graph.h:2757
bool remove_predecessor(predecessor_type &) __TBB_override
Decrements the trigger threshold.
Definition: flow_graph.h:605
concurrency
An enumeration the provides the two most common concurrency levels: unlimited and serial.
Definition: flow_graph.h:88
bool try_get(T &v) __TBB_override
Request an item from the buffer_node.
Definition: flow_graph.h:1932
bool remove_successor(successor_type &r) __TBB_override
Removes a successor from this node.
Definition: flow_graph.h:3576
multifunction_node(const multifunction_node &other)
Definition: flow_graph.h:1223

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