Go to main content
Oracle® Developer Studio 12.5: OpenMP API User's Guide

Exit Print View

Updated: July 2016
 
 

4.5 Task Dependence

The OpenMP 4.0 specification introduces the depend clause on the task directive, which enforces additional constraints on the scheduling of tasks. These constraints establish dependences between sibling tasks only. Sibling tasks are OpenMP tasks that are child tasks of the same task region.

When the in dependence-type is specified with the depend clause, 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. When the out or inout dependence-type is specified on the depend clause, 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.

The following example illustrates task dependence.

Example 5  Illustrating the depend Clause Synchronizing Only Sibling Tasks
% cat -n task_depend_01.c
     1  #include <omp.h>
     2  #include <stdio.h>
     3  #include <unistd.h>
     4
     5  int main()
     6  {
     7      int a,b,c;
     8
     9      #pragma omp parallel
    10      {
    11          #pragma omp master
    12          {
    13              #pragma omp task depend(out:a)
    14              {
    15                  #pragma omp critical
    16                  printf ("Task 1\n");
    17              }
    18
    19              #pragma omp task depend(out:b)
    20              {
    21                  #pragma omp critical
    22                  printf ("Task 2\n");
    23              }
    24
    25              #pragma omp task depend(in:a,b) depend(out:c)
    26              {
    27                  printf ("Task 3\n");
    28              }
    29
    30              #pragma omp task depend(in:c)
    31              {
    32                  printf ("Task 4\n");
    33              }
    34          }
    35          if (omp_get_thread_num () == 1)
    36            sleep(1);
    37      }
    38      return 0;
    39  }

% cc -xopenmp -O3 task_depend_01.c
% a.out
Task 2
Task 1
Task 3
Task 4

% a.out
Task 1
Task 2
Task 3
Task 4

In this example, Tasks 1, 2, 3, and 4 are all child tasks of the same implicit task region, and so are sibling tasks. Task 3 is a dependent task of Tasks 1 and 2 because of the dependences on the a argument specified in the depend clauses. Therefore, Task 3 cannot be scheduled until both Tasks 1 and 2 have completed. Similarly, Task 4 is a dependent task of task 3 so Task 4 cannot be scheduled until Task 3 has completed.

Note that the depend clause synchronizes sibling tasks only. The following example (Example 6) shows a case where the depend clause does not affect non-sibling tasks.

Example 6  Illustrating the depend Clause Not Affecting non-Sibling Tasks
% cat -n task_depend_02.c
     1  #include <omp.h>
     2  #include <stdio.h>
     3  #include <unistd.h>
     4
     5  int main()
     6  {
     7      int a,b,c;
     8
     9      #pragma omp parallel
    10      {
    11          #pragma omp master
    12          {
    13              #pragma omp task depend(out:a)
    14              {
    15                  #pragma omp critical
    16                  printf ("Task 1\n");
    17              }
    18
    19              #pragma omp task depend(out:b)
    20              {
    21                  #pragma omp critical
    22                  printf ("Task 2\n");
    23
    24                  #pragma omp task depend(out:a,b,c)
    25                  {
    26                    sleep(1);
    27                    #pragma omp critical
    28                    printf ("Task 5\n");
    29                  }
    30              }
    31
    32              #pragma omp task depend(in:a,b) depend(out:c)
    33              {
    34                  printf ("Task 3\n");
    35              }
    36
    37              #pragma omp task depend(in:c)
    38              {
    39                  printf ("Task 4\n");
    40              }
    41          }
    42          if (omp_get_thread_num () == 1)
    43            sleep(1);
    44      }
    45      return 0;
    46  }

% cc -xopenmp -O3 task_depend_02.c
% a.out
Task 1
Task 2
Task 3
Task 4
Task 5

In this above example, Task 5 is a child task of Task 2 and is not a sibling of Tasks 1, 2, 3 or 4. So, despite the depend clauses referencing the same variables (a, b, c), there is no dependence between Task 5 and Tasks 1, 2, 3, or 4.

4.5.1 Notes About Task Dependence

    Note the following tips about task dependence:

  • in, out, and inout dependence-types in the depend clause are similar to read and write operations, although the in, out and inout dependence-types are solely for establishing task dependences. They do not indicate any memory access patterns inside task regions. A task having a depend(in:a), depend(out:a), or depend(inout:a) clause may read or write variable a inside its region, or may even not access variable a at all.

  • Having both the if clause and the depend clause on the same task directive can be expensive when the condition of the if clause evaluates to false. When a task has an if(false) clause, the encountering thread must suspend the current task region until the generated task (the task with the if(false) clause) is completed. At the same time, the task scheduler should not schedule the generated task until its task dependences are fulfilled. Because the point immediately following the generation of an explicit task is a task scheduling point, the task scheduler will try to schedule tasks so that the task dependences of the undeferred task are fulfilled. Finding and scheduling the right tasks in the pool may be expensive. In the worst case, it can be as expensive as having a taskwait region.

  • List items used in depend clauses of the same task or sibling tasks must indicate identical storage or disjoint storage. Therefore, if array sections appear in depend clauses, make sure that the array sections indicate either identical or disjoint storage.