JavaScript is required to for searching.
ナビゲーションリンクをスキップ
印刷ビューの終了
Oracle Solaris Studio 12.3: OpenMP API ユーザーガイド     Oracle Solaris Studio 12.3 Information Library (日本語)
search filter icon
search icon

ドキュメントの情報

はじめに

1.  OpenMP API について

2.  OpenMP プログラムのコンパイルと実行

3.  実装によって定義される動作

4.  入れ子並列処理

5.  タスク化

6.  変数の自動スコープ宣言

6.1 自動スコープ宣言用データスコープ節

6.1.1 __auto

6.1.2 default(__auto)

6.2 並列構文のスコープ宣言の規則

6.2.1 スカラー変数に関するスコープ宣言規則

6.2.2 配列に関するスコープ宣言規則

6.3 task 構文のスコープ宣言規則

6.3.1 スカラー変数に関するスコープ宣言規則

6.3.2 配列に関するスコープ宣言規則

6.4 自動スコープ宣言に関する一般的な注意事項

6.5 制限事項

6.6 自動スコープ宣言結果の確認

6.7 自動スコープ宣言の例

7.  スコープチェック

8.  パフォーマンス上の検討事項

A.  指令での節の記述

索引

6.7 自動スコープ宣言の例

この節では、自動スコープ宣言規則がどのように使用されるかを、いくつかの例に示します。

例 6-4 より複雑な例

 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

関数 FOO() には並列領域が 1 つあり、この並列領域には、SINGLE 構文とワークシェアリングの DO 構文、CRITICAL 構文がそれぞれ 1 つあります。OpenMP 並列構文のほかに、並列領域内のコードは次のことを行います。

  1. 配列 X 内の値を配列 Y にコピーします。

  2. X 内の正の最大値を検出し、その値を M に格納します。

  3. X の一部要素の値を変数 W に蓄積します。

コンパイラはこれらの規則をどのように使用して、並列領域内の変数のスコープを正しく宣言するのでしょうか。

前述の並列領域では、INMMTWMX、および Y という変数が使用されています。コンパイラは次の情報を決定します。

例 6-5 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);

スカラー変数 p および q、およびポインタ変数データは、タスク構文でも並列領域でも読み取り専用です。 そのため、これらは TS1 に従って FIRSTPRIVATE と自動スコープ宣言されます。

例 6-6 フィボナッチのもう 1 つの例

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. }

スカラー n はタスク構文でも並列構文でも読み取り専用です。そのため、n は TS1 に従って FIRSTPRIVATE と自動スコープ宣言されます。

スカラー変数 x および y は、ローカル関数 fib() のローカル変数です。両方のタスクが x y にアクセスしても、データ競合は起こりません。taskwait があるため、2 つのタスクがまず実行を完了してから、タスクを検出した fib() を実行していたスレッドが fib() を終了します。これは、2 つのタスクの実行中に xy がアクティブであることを意味します。そのため、xy は、TS2 に従い、SHARED と自動スコープ宣言されます。

例 6-7 自動スコープ宣言のもう 1 つの例

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.   }

この例では、xx は並列領域の private 変数です。チームのスレッドの 1 つが task1 を実行して、xx の初期値を変更します。その後、すべてのスレッドが task2 を検出し、xx を使用して何らかの計算を行います。

task1 では、xx を使用しても、データ競合は発生しません。1 つの構文の終わりに暗黙的なバリアーがあり、このバリアーを出る前に task1 を完了する必要があるので、xxtask1 が実行している間でもアクティブなのです。したがって、TS2 に従い、xxtask1SHARED と自動スコープ宣言されます。

task2 では、xx は読み取り専用として使用されます。ただし、xx の使用は、包含する並列構文では読み取り専用ではありません。xx は、並列構文に対しては PRIVATE と事前定義されているので、task2 が実行している間でも xx がアクティブかどうかはわかりません。したがって、TS3 に従い、xxtask2FIRSTPRIVATE と自動スコープ宣言されます。

task2 では、yy を使用することでデータ競合が発生し、task2 を実行する各スレッドでは、変数 yy は同じスレッドによる読み取りの前に常に書き込まれます。そのため、TS4 に従い、yytask2 では PRIVATE と自動スコープ宣言されます。

例 6-8 最後の例

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.   }

task 構文では xx は読み取り専用として使用されないので、データ競合が発生します。しかし、タスク領域で x を読み取ると、タスク外で定義された x の値が取得されます(この例では、xx は並列領域に対して SHARED なので、x の定義は実際には並列領域外で行われます)。そのため、TS5 に従い、xxFIRSTPRIVATE と自動スコープ宣言されます。

task 構文での yy の使用は読み取り専用ではありませんが、データ競合は発生しません。taskwait が発生しているので、yy はタスクの実行中でもアクセスできます。そのため、TS2 に従い、yySHARED と自動スコープ宣言されます。