1.. _avoiding_data_races:
2
3Avoiding Data Races
4===================
5
6
7The edges in a flow graph make explicit the dependence relationships
8that you want the library to enforce. Similarly, the concurrency limits
9on ``function_node`` and ``multifunction_node`` objects limit the maximum number
10of concurrent invocations that the runtime library will allow. These are
11the limits that are enforced by the library; the library does not
12automatically protect you from data races. You must explicitly prevent
13data races by using these mechanisms.
14
15
16For example, the follow code has a data race because there is nothing to
17prevent concurrent accesses to the global count object referenced by
18node f:
19
20
21::
22
23
24     graph g;
25     int src_count = 1;
26     int global_sum = 0;
27     int limit = 100000;
28
29     input_node< int > src( g, [&]( oneapi::tbb::flow_control& fc ) -> int {
30       if ( src_count <= limit ) {
31         return src_count++;
32       } else {
33         fc.stop();
34         return int();
35       }
36     } );
37     src.activate();
38
39     function_node< int, int > f( g, unlimited, [&]( int i ) -> int {
40       global_sum += i;  // data race on global_sum
41       return i;
42     } );
43
44
45     make_edge( src, f );
46     g.wait_for_all();
47
48
49     cout << "global sum = " << global_sum
50          << " and closed form = " << limit*(limit+1)/2 << "\n";
51
52
53If you run the above example, it will likely calculate a global sum that
54is a bit smaller than the expected solution due to the data race. The
55data race could be avoided in this simple example by changing the
56allowed concurrency in ``f`` from unlimited to 1, forcing each value to be
57processed sequentially by ``f``. You may also note that the ``input_node`` also
58updates a global value, ``src_count``. However, since an ``input_node`` always
59executes serially, there is no race possible.
60