• 2021.4
  • 09/27/2021
  • Public Content

Avoiding Data Races

The edges in a flow graph make explicit the dependence relationships that you want the library to enforce. Similarly, the concurrency limits on
objects limit the maximum number of concurrent invocations that the runtime library will allow. These are the limits that are enforced by the library; the library does not automatically protect you from data races. You must explicitly prevent data races by using these mechanisms.
For example, the follow code has a data race because there is nothing to prevent concurrent accesses to the global count object referenced by node f:
graph g; int src_count = 1; int global_sum = 0; int limit = 100000; input_node< int > src( g, [&]( oneapi::tbb::flow_control& fc ) -> int { if ( src_count <= limit ) { return src_count++; } else { fc.stop(); return int(); } } ); src.activate(); function_node< int, int > f( g, unlimited, [&]( int i ) -> int { global_sum += i; // data race on global_sum return i; } ); make_edge( src, f ); g.wait_for_all(); cout << "global sum = " << global_sum << " and closed form = " << limit*(limit+1)/2 << "\n";
If you run the above example, it will likely calculate a global sum that is a bit smaller than the expected solution due to the data race. The data race could be avoided in this simple example by changing the allowed concurrency in
from unlimited to 1, forcing each value to be processed sequentially by
. You may also note that the
also updates a global value,
. However, since an
always executes serially, there is no race possible.

Product and Performance Information


Performance varies by use, configuration and other factors. Learn more at www.Intel.com/PerformanceIndex.