JavaScript is required to for searching.
Skip Navigation Links
Exit Print View
Oracle Solaris Studio 12.3: OpenMP API User's Guide     Oracle Solaris Studio 12.3 Information Library
search filter icon
search icon

Document Information

Preface

1.  Introducing the OpenMP API

2.  Compiling and Running OpenMP Programs

3.  Implementation-Defined Behaviors

4.  Nested Parallelism

5.  Tasking

6.  Automatic Scoping of Variables

6.1 Autoscoping Data Scope Clause

6.1.1 __auto Clause

6.1.2 default(__auto) Clause

6.2 Scoping Rules for a Parallel Construct

6.2.1 Scoping Rules for Scalar Variables

6.2.2 Scoping Rules for Arrays

6.3 Scoping Rules for a task Construct

6.3.1 Scoping Rules for Scalar Variables

6.3.2 Scoping Rules for Arrays

6.4 General Comments About Autoscoping

6.5 Restrictions

6.6 Checking the Results of Autoscoping

6.7 Autoscoping Examples

7.  Scope Checking

8.  Performance Considerations

A.  Placement of Clauses on Directives

Index

6.7 Autoscoping Examples

This section provides some examples to illustrate how the autoscoping rules work.

Example 6-4 A More Complicated Example

 1.      REAL FUNCTION FOO (N, X, Y)
 2.      INTEGER       N, I
 3.      REAL          X(*), Y(*)
 4.      REAL          W, MM, M
 5.
 6.      W = 0.0
 7.
 8. C$OMP PARALLEL DEFAULT(__AUTO)
 9.
10. C$OMP SINGLE
11.       M = 0.0
12. C$OMP END SINGLE
13.
14.       MM = 0.0
15.
16. C$OMP DO
17.       DO I = 1, N
18.          T = X(I)
19.          Y(I) = T
20.          IF (MM .GT. T) THEN
21.             W = W + T
22.             MM = T
23.          END IF
24.       END DO
25. C$OMP END DO
26.
27. C$OMP CRITICAL
28.       IF ( MM .GT. M ) THEN
29.          M = MM
30.       END IF
31. C$OMP END CRITICAL
32.
33. C$OMP END PARALLEL
34.
35.      FOO = W - M
36.
37.      RETURN
38.      END

The function FOO() contains a parallel region, which contains a SINGLE construct, a work-sharing DO construct and a CRITICAL construct. Besides the OpenMP parallel constructs, the code in the parallel region does the following:

  1. Copy the value in array X to array Y

  2. Find the maximum positive value in X, and store it in M

  3. Accumulate the value of some elements of X into variable W.

How does the compiler use the these rules to correctly scope the variables in the parallel region?

The following variables are used in the parallel region, I, N, MM, T, W, M, X, and Y. The compiler will determine the following information:

Example 6-5 Example With QuickSort

static void par_quick_sort (int p, int r, float *data)
{
   if (p < r) 
   {
      int q = partition (p, r, data);  
      
      #pragma omp task default(__auto) if ((r-p)>=low_limit)
      par_quick_sort (p, q-1, data);

      #pragma omp task default(__auto) if ((r-p)>=low_limit)
      par_quick_sort (q+1, r, data);
   }
}

int main ()
{
  ...
  #pragma omp parallel
  {
     #pragma omp single nowait
     par_quick_sort (0, N-1, &Data[0]);
  }
  ...
}

er_src result:

      Source OpenMP region below has tag R1
      Variables autoscoped as FIRSTPRIVATE in R1: p, q, data
      Firstprivate variables in R1: data, p, q
        47. #pragma omp task default(__auto) if ((r-p)>=low_limit)
        48. par_quick_sort (p, q-1, data);
      
      Source OpenMP region below has tag R2
      Variables autoscoped as FIRSTPRIVATE in R2: q, r, data
      Firstprivate variables in R2: data, q, r
        49. #pragma omp task default(__auto) if ((r-p)>=low_limit)
        50. par_quick_sort (q+1, r, data);

The scalar variables p and q, and the pointer variable data, are read-only in the task construct, and read-only in the parallel region. Therefore, they are autoscoped as FIRSTPRIVATE according to TS1.

Example 6-6 Another Fibbonacci Example

int fib (int n)
{
   int x, y;
   if (n < 2) return n;

   #pragma omp task default(__auto)
   x = fib(n - 1);

   #pragma omp task default(__auto)
   y = fib(n - 2);

   #pragma omp taskwait
   return x + y;
}

er_src result:

   Source OpenMP region below has tag R1
   Variables autoscoped as SHARED in R1: x
   Variables autoscoped as FIRSTPRIVATE in R1: n
   Shared variables in R1: x
   Firstprivate variables in R1: n
    24.         #pragma omp task default(__auto) /* shared(x) firstprivate(n) */
    25.         x = fib(n - 1);
   
   Source OpenMP region below has tag R2
   Variables autoscoped as SHARED in R2: y
   Variables autoscoped as FIRSTPRIVATE in R2: n
   Shared variables in R2: y
   Firstprivate variables in R2: n
    26.         #pragma omp task default(__auto) /* shared(y) firstprivate(n) */
    27.         y = fib(n - 2);
    28. 
    29.         #pragma omp taskwait
    30.         return x + y;
    31. }

Scalar n is read-only in the task constructs and read-only in the parallel construct. Therefore, n is autoscoped as FIRSTPRIVATE, according to TS1.

Scalar variables x and y are local variables of function fib(). Accesses to x and y in both tasks are free of data race. Because there is a taskwait, the two tasks will complete execution before the thread executing fib(), which encountered the tasks, exits fib(). This implies that x and y will be active while the two tasks are executing. Therefore, x and y are autoscoped as SHARED, according to TS2.

Example 6-7 Another Autoscoping Example

int main(void)
{
  int yy = 0;

  #pragma omp parallel default(__auto) shared(yy)
  {
    int xx = 0;

    #pragma omp single
    {
       #pragma omp task default(__auto) // task1
       {
          xx = 20;
       }
    }

    #pragma omp task default(__auto) // task2
    {
       yy = xx;
    }
  }

  return 0;
}

er_src result:

   Source OpenMP region below has tag R1
   Variables autoscoped as PRIVATE in R1: xx
   Private variables in R1: xx
   Shared variables in R1: yy
     7.   #pragma omp parallel default(__auto) shared(yy)
     8.   {
     9.     int xx = 0;
    10.

   Source OpenMP region below has tag R2
    11.     #pragma omp single
    12.     {

   Source OpenMP region below has tag R3
   Variables autoscoped as SHARED in R3: xx
   Shared variables in R3: xx
    13.        #pragma omp task default(__auto) // task1
    14.        {
    15.           xx = 20;
    16.        }
    17.     }
    18.

   Source OpenMP region below has tag R4
   Variables autoscoped as PRIVATE in R4: yy
   Variables autoscoped as FIRSTPRIVATE in R4: xx
   Private variables in R4: yy
   Firstprivate variables in R4: xx
    19.     #pragma omp task default(__auto) // task2
    20.     {
    21.        yy = xx;
    22.     }
    23.   }

In this example, xx is a private variable in the parallel region. One of the threads in the team modifies its initial value of xx by executing task1. Then all of the threads encounter task2, which uses xx to do some computation.

In task1, the use of xx is free of data race. Because an implicit barrier is at the end of the single construct and task1 should complete before exiting this barrier, xx will be active while task1 is executing. Therefore, according to TS2, xx is autoscoped as SHARED on task1.

In task2, the use of xx is read-only. However, the use of xx is not read-only in the enclosing parallel construct. Because xx is predetermined as PRIVATE for the parallel construct, whether xx will be active while task2 is executing is not certain. Therefore, according to TS3, xx is autoscoped FIRSTPRIVATE on task2.

In task2, the use of yy is not free of data race, and in each thread executing task2, the variable yy is always written before being read by the same thread. So, according to TS4, yy is autoscoped PRIVATE on task2.

Example 6-8 A Final Example

int foo(void)
{
  int xx = 1, yy = 0;

  #pragma omp parallel shared(xx,yy)
  {
    #pragma omp task default(__auto)
    {
       xx += 1;

       #pragma omp atomic
       yy += xx;
    }

    #pragma omp taskwait
  }
  return 0;
}

er_src result:

   Source OpenMP region below has tag R1
   Shared variables in R1: yy, xx
     5.   #pragma omp parallel shared(xx,yy)
     6.   {

   Source OpenMP region below has tag R2
   Variables autoscoped as SHARED in R2: yy
   Variables autoscoped as FIRSTPRIVATE in R2: xx
   Shared variables in R2: yy
   Firstprivate variables in R2: xx
     7.     #pragma omp task default(__auto)
     8.     {
     9.        xx += 1;
    10.
    11.        #pragma omp atomic
    12.        yy += xx;
    13.     }
    14.
    15.     #pragma omp taskwait
    16.   }

The use of xx in the task construct is not read-only and is not free of data race. However the read of x in the task region gets the value of x defined outside the task. (In this example, because xx is SHARED for the parallel region, the definition of x is actually outside the parallel region.) Therefore, according to TS5, xx is autoscoped as FIRSTPRIVATE.

The use of yy in the task construct is not read-only but is free of data race. yy will be accessible while the task is executing because there is a taskwait. Therefore, according to TS2, yy is autoscoped as SHARED.