Occurs when a task writes a value that a different (child) task reads. A child task is a task nested inside another task.

ID |
Code Location |
Description |
|---|---|---|
1 |
Allocation site |
If present, represents the location and associated call stack when the memory block was allocated. |
2 |
Parallel site |
Represents the location and associated call stack of the parallel site containing the Data Communication problem. |
3 |
Write |
Represents the instruction and associated call stack where the memory was written. |
4 |
Read |
Represents the instruction and associated call stack where the memory was read in a different task execution. |
void problem()
{
int* pointer = new int; // Allocation site
ANNOTATE_SITE_BEGIN(datacomm_site1); // Begin parallel site
ANNOTATE_TASK_BEGIN(task1);
*pointer = 999; // Write
ANNOTATE_TASK_END();
assert(*pointer == 999); // Read
ANNOTATE_SITE_END();
}In this example, one task writes a heap-allocated int, then an ancestor task reads it.
void data_communication()
{
ANNOTATE_SITE_BEGIN(data_communication_site); // Parallel site
{
for (int i=0; i<N; i++) {
ANNOTATE_TASK_BEGIN(data_communication_task1);
{
communication++; /* write in child */ // Write
}
ANNOTATE_TASK_END();
printf("%d\n", communication); /* read in parent */ // Read
}
ANNOTATE_SITE_END();
}In this example, the incremented variable is read after each task. This creates a serial dependence.
If you can preserve the application's integrity, consider moving the reads by the parent task into the child task. In the example above, this would result in non-deterministic output. If moving the read is not possible, you may need to use a different strategy, such as pipelining the loop.