This example calculates the sum x*x + x*x*x for all x = 1 to 10. The layout of this example is shown in the figure below.

A simple message flow graph.
A simple flow graph.

Each value enters through the input_node<int> input. This node broadcasts the value to both squarer and cuber, which calculate x*x and x*x*x respectively. The output of each of these nodes is put to one of join's ports. A tuple containing both values is created by join_node< tuple<int,int> > join and forwarded to summer, which adds both values to the running total. Both squarer and cuber allow unlimited concurrency, that is they each may process multiple values simultaneously. The final summer, which updates a shared total, is only allowed to process a single incoming tuple at a time, eliminating the need for a lock around the shared value.

#include <cstdio>
#include "tbb/flow_graph.h"

using namespace tbb::flow;

struct square {
  int operator()(int v) { return v*v; }
};

struct cube {
  int operator()(int v) { return v*v*v; }
};

class sum {
  int &my_sum;
public:
  sum( int &s ) : my_sum(s) {}
  int operator()( tuple< int, int > v ) {
    my_sum += get<0>(v) + get<1>(v);
    return my_sum;
  }
};

int main() {
  int result = 0;

  graph g;
  broadcast_node<int> input(g);
  function_node<int,int> squarer( g, unlimited, square() );
  function_node<int,int> cuber( g, unlimited, cube() );
  join_node< tuple<int,int>, queueing > join( g );
  function_node<tuple<int,int>,int>
      summer( g, serial, sum(result) );

  make_edge( input, squarer );
  make_edge( input, cuber );
  make_edge( squarer, get<0>( join.input_ports() ) );
  make_edge( cuber, get<1>( join.input_ports() ) );
  make_edge( join, summer );

  for (int i = 1; i <= 10; ++i)
      input.try_put(i);
  g.wait_for_all();

  printf("Final result is %d\n", result);
  return 0;
}

In the example code above, the classes square, cube and sum define the three user-defined operations. Each class is used to create a function_node.

In function main, the flow graph is set up and then the values 1-10 are put into the node input. All the nodes in this example pass around values of type int. The nodes used in this example are all class templates and therefore can be used with any type that supports copy construction, including pointers and objects.

CAUTION

Values are copied as they pass between nodes and therefore passing around large objects should be avoided. To avoid large copy overheads, pointers to large objects can be passed instead.

Note

This is a simple syntactic example only. Since each node in a flow graph may execute as an independent task, the granularity of each node should follow the general guidelines for tasks as described in Section 3.2.3 of the Intel® Threading Building Blocks Tutorial.

The classes and functions used in this example are described in detail in topics linked from the Flow Graph parent topic.

Para obter informações mais completas sobre otimizações do compilador, consulte nosso aviso de otimização.