The following code works based on the OpenMP 4.0 specification:
The out and inout dependence-types. The generated task will be a dependent task of all previously generated sibling tasks that reference at least one of the list items in an in, out, or inout dependence-type list.
This means that task3 becomes dependent of task2. Right? but it does not make sense! Why should an input-output dependency task be a dependent of an input dependency task?
What do I need to do in order to make them independent? p.s: code tested with g++ 4.9 on Linux.
#include <stdio.h>
#include <omp.h>
#include <unistd.h>
int main() {
int x,y;
#pragma omp parallel num_threads(10)
{
#pragma omp single nowait
{
#pragma omp task depend (out:x) //task1
{
x=1;
}
#pragma omp task depend(in:x) depend(out:y) //task2
{
sleep(2); //Does task3 wait for us? Yes!
y=x+1;
}
#pragma omp task depend (inout:x) //task3
{
x++;
printf("task3(x): %d\n" , x);
}
#pragma omp task depend (in:x,y) //task4
{
printf("task4 (x+y): %d\n" , x+y);
}
}
}
return 0;
}
An OpenMP task is a single line of code or a structured block which is immediately “written down” in a list of tasks. • The new task can be executed immediately, or it can be deferred.
OpenMP 3.0 introduced a new feature called tasking. Tasking allows for the parallelization of applications where units of work are generated dynamically, such as in recursive structures or while loops, without having to rely on nested parallelism [3].
single has an implicit barrier upon completion of the region, where all threads wait for synchronization, while master doesn't have any.
Defines a region of structured blocks that will be distributed among the threads in a team.
Question 1 : This means that task3 becomes dependent of task2. Right?
According to the OpenMP 4.0 standard on the depend
clause (emphasis mine):
Task dependences are derived from the dependence-type of a
depend
clause and its list items, where dependence-type is one of the following:The in dependence-type. The generated task will be a dependent task of all previously generated sibling tasks that reference at least one of the list items in an out or inout dependence-type list.
The out and inout dependence-types. The generated task will be a dependent task of all previously generated sibling tasks that reference at least one of the list items in an in, out, or inout dependence-type list.
From this description follows that:
depend(in:x)
will generate a task dependent on all the previously generated tasks with depend(out:x)
or depend(inout:x)
depend(out:x)
or the clause depend(inoout:x)
will generate a task dependent on all the previously generated tasks mentioning x
in a depend
clauseApplying this to your specific case gives a chain of dependencies of this kind:
task1 (out:x) -> task2 (in:x,out:y) -> task4 (in:x,y)
| ^
| |
> task3 (inout:x)
Therefore task3 depends on the completion of task2.
Question 2 : Why should an input-output dependency task be a dependent of an input dependency task?
I would just let you notice that with this rule you will have a deterministic value of your variables x
and y
at the end of the run (assuming you take care of synchronizing accesses to memory). If task3 was dependent on task1 instead of task2, this determinism wouldn't hold (and an inout
dependency would have been equivalent to an in
dependency).
Question 3 : What do I need to do in order to make them independent?
Turn the inout:x
dependency into an in:x
dependency and synchronize accesses to x
via atomic
clauses. That way you will have runs in which either:
x == 2
and y == 2
x == 2
and y == 3
depending on whether task2 executes before task3 or not.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With