XL Fortran for AIX V8.1.1

ランゲージ・リファレンス


SMP ディレクティブの詳細な説明

次の節は、XL Fortran でサポートされているすべての SMP ディレクティブをアルファベット順にリストしています。ディレクティブ文節については、SMP ディレクティブ文節を参照してください。

ATOMIC

ATOMIC ディレクティブを使用して、並列領域内の特定のメモリー位置を安全に更新することができます。 ATOMIC を使用する場合は、同時にメモリー位置に書き込むスレッドは 1 つだけにして、同じメモリー位置への同時書き込みによって生じることのあるエラーを避ける必要があります。

通常、共用変数が同時に複数のスレッドによって更新されている場合は、 CRITICAL 構造体内で共用変数を保護します。ただし、特定のプラットフォームは、変数を更新するためにアトミック・オペレーションをサポートしています。たとえば、1 つのアトミック・アクションで、メモリー位置から読み取りを行い何かを計算してその位置に書き込むハードウェア命令をサポートしているプラットフォームもあります。 ATOMIC ディレクティブは、可能な場合はアトミック・オペレーションを使用するようコンパイラーに指示します。このようにしないと、コンパイラーは他の機構を使用してアトミック更新を実行します。

ATOMIC ディレクティブが有効なのは、 -qsmp コンパイラー・オプションが指定されているときに限られます。

構文



>>-ATOMIC------------------------------------------------------><
 
 
>>-atomic_statement--------------------------------------------><
 
 

atomic_statement の意味は次のとおりです。



>>-+-update_variable--=--update_variable--operator--expression-----------+-><
   +-update_variable--=--expression--operator--update_variable-----------+
   +-update_variable--=--intrinsic--(--update_variable--,--expression--)-+
   '-update_variable--=--intrinsic--(--expression--,--update_variable--)-'
 
 

update_variable
組み込みタイプのスカラー変数です。

intrinsic
maxminiandior または ieor のいずれかです。

operator
+-*/.AND..OR..EQV..NEQV. または .XOR. のいずれかです。

expression
update_variable を参照しないスカラー式です。

規則

ATOMIC ディレクティブは、直後に続くステートメントだけに適用されます。

atomic_statement の中の expression は、自動的には評価されません。その計算で競合状態がないようにする必要があります。

ATOMIC ディレクティブを使用し作成されたプログラム全体内の update_variable のストレージ・ロケーションに対するすべての参照は、同じタイプおよび同じ型付きパラメーターを持っている必要があります。

関数 intrinsic、演算子 operator、および割り当ては、組み込み関数、演算子、および割り当てでなければならず、再定義された組み込み関数、定義済み演算子または定義済み割り当てであってはなりません。

例 1: 次の例では、複数のスレッドがカウンターを更新しています。 ATOMIC は、すべての更新がカウントされるようにするために使用されています。

      PROGRAM P
        R = 0.0
!$OMP   PARALLEL DO SHARED(R)
        DO I=1, 10
!$OMP     ATOMIC
          R = R + 1.0
        END DO
        PRINT *,R
      END PROGRAM P
 

次のような出力になります。

10.0

例 2: 次の例では、配列 Y のどのエレメントがそれぞれの繰り返しで更新されるのかが確かではないので、 ATOMIC ディレクティブが必須です。

      PROGRAM P
        INTEGER, DIMENSION(10) :: Y, INDEX
        INTEGER B
        Y = 5
        READ(*,*) INDEX, B
!$OMP   PARALLEL DO SHARED(Y)
        DO I = 1, 10
!$OMP     ATOMIC
          Y(INDEX(I)) = MIN(Y(INDEX(I)),B)
        END DO
        PRINT *, Y
      END PROGRAM P
 

入力データ:

10 10 8 8 6 6 4 4 2 2   4
 

次のような出力になります。

5 4 5 4 5 4 5 4 5 4
 

例 3: 次の例は、配列を参照するために ATOMIC 命令を使用することはできないので無効です。

       PROGRAM P
      	REAL ARRAY(10)
         ARRAY = 0.0
!$OMP 	PARALLEL DO SHARED(ARRAY)
           DO I = 1, 10
!$OMP   		  ATOMIC
             ARRAY = ARRAY + 1.0
           END DO
        PRINT *, ARRAY
      END PROGRAM P

例 4: 次の例は無効です。 expressionupdate_variable を参照してはなりません。

		 PROGRAM P
         R = 0.0
!$OMP		PARALLEL DO SHARED(R)
           DO I = 1, 10
!$OMP   			ATOMIC
              R = R + R
           END DO
        PRINT *, R
      END PROGRAM P
 

関連情報

BARRIER

BARRIER ディレクティブによって、チーム内のすべてのスレッドを同期化することができます。スレッドが BARRIER ディレクティブを検出すると、チーム内の他のすべてのスレッドが同じ点に達するまで待ちます。

BARRIER ディレクティブが有効なのは、 -qsmp コンパイラー・オプションが指定されているときに限られます。

構文



>>-BARRIER-----------------------------------------------------><
 
 

規則

BARRIER ディレクティブは、最も近いところにある動的に対になっている PARALLEL ディレクティブがあれば、それをバインドします。

BARRIER ディレクティブは、CRITICALDO (作業共用)、MASTERPARALLEL DOPARALLEL SECTIONSSECTIONSSINGLE、および WORKSHARE ディレクティブの動的エクステント内に指定することはできません。

スレッドの 1 つが BARRIER ディレクティブを検出すると、チーム内のすべてのスレッドがこのディレクティブを検出しなければなりません。

すべての BARRIER ディレクティブと作業共用構造体は、チーム内のすべてのスレッドによって同じ順序で検出されなければなりません。

チーム内のスレッドを同期化することに加えて、BARRIER ディレクティブは FLUSH ディレクティブを暗黙指定します。

例 1: PARALLEL ディレクティブにバインドされる BARRIER ディレクティブの例です。注: "c" を計算するために、「a」および 「b」が完全に割り当てられていることを確認する必要があるため、スレッドは待つ必要があります。

      SUBROUTINE SUB1
      INTEGER A(1000), B(1000), C(1000)
!$OMP PARALLEL
!$OMP DO
      DO I = 1, 1000
        A(I) = SIN(I*2.5)
      END DO
!$OMP END DO NOWAIT
!$OMP DO
      DO J = 1, 10000
        B(J) = X + COS(J*5.5)
      END DO
!$OMP END DO NOWAIT
         ...
!$OMP BARRIER
      C = A + B
!$OMP END PARALLEL
      END

例 2: CRITICAL セクション内で間違って使用されている BARRIER ディレクティブの例。 CRITICAL セクションに入ることができるのは、一度に 1 つのスレッドのみであるため、デッドロックになることがあります。

!$OMP PARALLEL DEFAULT(SHARED)
 
!$OMP CRITICAL
      DO I = 1, 10
        X= X + 1
!$OMP   BARRIER
        Y= Y + I*I
      END DO
!$OMP END CRITICAL
!$OMP END PARALLEL

関連情報

CRITICAL / END CRITICAL

CRITICAL 構造体では、一度に最大 1 つのスレッドによって実行されるコードの独立したブロックを定義できます。 CRITICAL 構造には、CRITICAL ディレクティブを入れ、その後にコードのブロックを続けて、最後は END CRITICAL ディレクティブで終了します。

CRITICAL および END CRITICAL ディレクティブが有効なのは、 -qsmp コンパイラー・オプションが指定されているときに限られます。

構文



>>-CRITICAL--+-----------------+-------------------------------><
             '-(--lock_name--)-'
 
 
>>-block-------------------------------------------------------><
 
 
>>-END CRITICAL--+-----------------+---------------------------><
                 '-(--lock_name--)-'
 
 

lock_name
コードの各種 CRITICAL 構造体を区別するための名前です。

block
一度に最大 1 つのスレッドによって実行されるコードのブロックを表します。

規則

任意指定の lock_name は、グローバルに適用される名前です。同じ実行可能プログラム内の他のグローバル・エンティティーを識別するために、lock_name を使用することはできません。

lock_nameCRITICAL ディレクティブに指定されている場合、同じ lock_name を対応する END CRITICAL ディレクティブに指定しなければなりません。

同じ lock_name が複数の CRITICAL 構造体に指定されている場合、一度に 1 つのスレッドだけが CRITICAL 構造体のいずれか 1 つを実行することになります。複数の CRITICAL 構造体に異なる lock_names がある場合、これらの構造体は並列して実行できます。

明示的な lock_name のない CRITICAL 構造体は、すべて同じロックによって保護されます。つまり、これらの CRITICAL 構造体には、コンパイラーによって同じ lock_name が割り当てられるため、一度に 1 つのスレッドだけが無名の CRITICAL 構造体に入ることになります。

lock_name は、クラス 1 のローカル・エンティティーと同じ名前を共用してはなりません。

CRITICAL 構造体に分岐したり、CRITICAL 構造体から分岐したりすることはできません。

CRITICAL 構造体は、プログラム内のどこにでも置けます。

CRITICAL 構造体を CRITICAL 構造体内にネストさせることは可能ですが、デッドロック状態が発生する恐れがあります。 -qsmp=rec_locks コンパイラー・オプションを指定すると、デッドロックを避けることができます。詳細については、「ユーザーズ・ガイド」を参照してください。

CRITICAL および END CRITICAL ディレクティブは、 FLUSH ディレクティブを暗黙指定します。

例 1: この例では、CRITICAL 構造体が、 PARALLEL DO ディレクティブによってマークされた DO ループ内に置かれていることに注意してください。

      EXPR=0
!OMP$ PARALLEL DO PRIVATE (I)
      DO I = 1, 100
!OMP$   CRITICAL
          EXPR = EXPR + A(I) * I
!OMP$   END CRITICAL
      END DO

例 2: この例では、CRITICAL 構造体に lock_name を指定しています。

!SMP$ PARALLEL DO PRIVATE(T)
      DO I = 1, 100
        T = B(I) * B(I-1)
!SMP$   CRITICAL (LOCK)
          SUM = SUM + T
!SMP$   END CRITICAL (LOCK)
      END DO

関連情報

DO / END DO

DO (作業共用) 構造体によって、それを検出するチームのメンバー間で、ループの実行を分割することができます。 END DO ディレクティブによって、DO (作業共用) ディレクティブで指定した DO ループの終わりを示すことができます。

DO (作業共用) および END DO ディレクティブが有効なのは、-qsmp コンパイラー・オプションが指定されているときに限られます。

構文



        .----------------------.
        V                      |
>>- DO----+------------------+-+-------------------------------><
          '-+---+--do_clause-'
            '-,-'
 
 
>>-do_loop-----------------------------------------------------><
 
 
>>-+---------------------+-------------------------------------><
   '-END DO--+---------+-'
             '- NOWAIT-'
 
 

do_clause の意味は次のとおりです。



>>-+-firstprivate_clause-+-------------------------------------><
   +-lastprivate_clause--+
   +-ordered_clause------+
   +-private_clause------+
   +-reduction_clause----+
   '-schedule_clause-----'
 
 

firstprivate_clause
FIRSTPRIVATEを参照してください。

lastprivate_clause
LASTPRIVATEを参照してください。

ordered_clause
ORDEREDを参照してください。

private_clause
PRIVATEを参照してください。

reduction_clause
REDUCTIONを参照してください。

schedule_clause
SCHEDULEを参照してください。

規則

DO (作業共用) ディレクティブに続く最初の非注釈行 (他のディレクティブは含まない) は、DO ループでなければなりません。この行は、無限の DO または DO WHILE ループにすることはできません。 DO (作業共用) ディレクティブは、ディレクティブの直後にある DO ループにのみ適用され、ネストされた DO ループには適用されません。

END DO ディレクティブは任意指定です。 END DO ディレクティブを使用する場合、DO ループの直後に指定しなければなりません。

1 つの DO 構造体に、複数の DO ステートメントが入っていてもかまいません。 DO ステートメントが同じ DO 終了ステートメントを共用しており、 END DO ディレクティブが構造体に続いている場合は、作業共用 DO ディレクティブは、構造体の最外部の DO ステートメントにだけ指定できます。

END DO ディレクティブに NOWAIT を指定すると、早い時期にループの反復を完了させるスレッドは、ループに続く指示よりも前に実行されます。スレッドは、同じチームの他のスレッドが DO ループを完了するのを待ちません。 END DO ディレクティブに NOWAIT を指定しないと、各スレッドは、DO ループの最後にある同一のチーム内の他のスレッドをすべて待ちます。

NOWAIT 文節を指定しない場合は、 END DO ディレクティブによって FLUSH ディレクティブが暗黙指定されます。

スレッドの 1 つが DO (作業共用) ディレクティブを検出すると、チーム内のすべてのスレッドがこのディレクティブを検出しなければなりません。 DO ループのループ境界とステップ値は、チーム内のそれぞれのスレッドについて同じでなければなりません。検出されるすべての作業共用構造体と BARRIER ディレクティブは、チーム内のすべてのスレッドによって同じ順序で検出されなければなりません。

DO (作業共用) ディレクティブは、CRITICAL または MASTER 構造体の動的エクステント内に指定することはできません。さらに、PARALLEL 構造体の動的エクステント内にあるのでない限り、 PARALLEL SECTIONS 構造体、作業共用構造体、または PARALLEL DO ループの動的エクステント内のに入れることはできません。

DO (作業共用) ディレクティブの後に、別の DO (作業共用) ディレクティブを続けて指定することはできません。特定の DO ループに指定できる DO (作業共用) ディレクティブは 1 つだけです。

DO (作業共用) ディレクティブは、特定の DO ループの INDEPENDENT または DO SERIAL ディレクティブに指定することはできません。

例 1: PARALLEL 構造体内の、独立しているいくつかの DO ループの例。 END DO ディレクティブに NOWAIT が指定されているため、最初の作業同期 DO ループの後に、同期は実行されません。

!$OMP PARALLEL
!$OMP DO
      DO I = 2, N
        B(I)= (A(I) + A(I-1)) / 2.0
      END DO
!$OMP END DO NOWAIT
!$OMP DO
      DO J = 2, N
         C(J) = SQRT(REAL(J*J))
      END DO
!$OMP END DO
      C(5) = C(5) + 10
!$OMP END PARALLEL
      END
 

例 2: SHARED、および SCHEDULE 文節の例。

!$OMP PARALLEL SHARED(A)
!$OMP DO SCHEDULE(STATIC,10)
      DO I = 1, 1000
         A(I) = 1 * 4
      END DO
!$OMP END DO
!$OMP END PARALLEL

例 3: 最も近い、対になっている PARALLEL ディレクティブにバインドする、MASTER および DO (作業共用) ディレクティブの両方の例。

!$OMP PARALLEL DEFAULT(PRIVATE)
      Y = 100
!$OMP MASTER
      PRINT *, Y
!$OMP END MASTER
!$OMP DO
      DO I = 1, 10
         X(I) = I
         X(I) = X(I) + Y
      END DO
!$OMP END PARALLEL
      END
 

例 4: DO (作業共用) ディレクティブの FIRSTPRIVATE および LASTPRIVATE 文節の両方の例。

      X = 100
 
!$OMP PARALLEL PRIVATE(I), SHARED(X,Y)
!$OMP DO FIRSTPRIVATE(X), LASTPRIVATE(X)
      DO I = 1, 80
         Y(I) = X + I
         X = I
      END DO
!$OMP END PARALLEL
      END

例 6: 共通 DO 終了ステートメントのあるネストされた DO ステートメントに適用された有効な作業共用 DO ディレクティブの例

!$OMP DO              ! A work-sharing DO directive can ONLY
                      ! precede the outermost DO statement.
      DO 100 I= 1,10
 
! !$OMP DO **Error**  ! Placing the OMP DO directive here is
                      ! invalid
 
        DO 100 J= 1,10
 
!         ...
 
100   CONTINUE
!$OMP END DO

関連情報

DO SERIAL

DO SERIAL ディレクティブは、ディレクティブの直後に続く DO ループを並列処理しないようにコンパイラーに指示します。このディレクティブは、特定の DO ループの自動並列化をブロックするときに便利です。 DO SERIAL ディレクティブが有効なのは、 -qsmp コンパイラー・オプションが指定されているときに限られます。

構文



>>-DO SERIAL---------------------------------------------------><
 
 

規則

DO SERIAL ディレクティブに続く最初の非注釈行 (他のディレクティブは含まない) は、 DO ループでなければなりません。 DO SERIAL ディレクティブは、ディレクティブの直後にある DO ループにのみ適用され、ループ内でネストされているループには適用されません。

特定の DO ループに指定できる DO SERIAL ディレクティブは 1 つだけです。 DO SERIAL ディレクティブは、DO または PARALLEL DO ディレクティブとともに同一の DO ループに指定することはできません。

DOSERIAL の間のホワイト・スペースはオプションです。

このディレクティブとともに OpenMP トリガー定数を使用しないでください。

例 1: 内部ループ (J ループ) が並列処理されない、ネストされた DO ループの例です。

!$OMP PARALLEL DO PRIVATE(S,I), SHARED(A)
      DO I=1, 500
        S=0
        !SMP$ DOSERIAL
        DO J=1, 500
          S=S+1
        ENDDO
        A(I)=S+I
      ENDDO
 

例 2: ネストされたループに適用されている DOSERIAL ディレクティブの例です。この場合、自動並列化が使用可能になっていれば、I または K ループが並列化されることがあります。

      DO I=1, 100
!SMP$ DOSERIAL
        DO J=1, 100
          DO K=1, 100
            ARR(I,J,K)=I+J+K
          ENDDO
        ENDDO
      ENDDO

関連情報

FLUSH

FLUSH ディレクティブを使用すると、それぞれのスレッドは他のスレッドによって生成されたデータにアクセスできるようになります。このディレクティブは、プログラムが最適化されると、コンパイラーはプロセッサー・レジスターに値を保持することがあるので必須です。 FLUSH ディレクティブを使用すると、それぞれのスレッド・ビューが一致しているということをメモリーがイメージできるようにします。

FLUSH ディレクティブが有効なのは、 -qsmp コンパイラー・オプションが指定されているときに限られます。

VOLATILE 属性の代わりに FLUSH ディレクティブを使用することによって、プログラムのパフォーマンスを向上させることができます。 VOLATILE 属性文節を使用すると、更新が行われた後と使用される前は常に変数がフラッシュされますが、 FLUSH を使用すると、変数のメモリーへの書き込みとメモリーからの読み込みは、指定した時だけ行われます。

構文



>>-FLUSH--+--------------------------+-------------------------><
          '-(--variable_name_list--)-'
 
 

規則

このディレクティブは、コード内のどこにでも指定することができます。ただし、並列領域の動的エクステントの外側で指定すると無効です。

variable_name_list を指定すると、メモリーへの書き込みとメモリーからの読み取りの対象となるのは、そのリストの中の変数だけになります (変数の書き込みまたは読み取りはまだ行われていないものと想定されます)。 variable_name_list の中のすべての変数は、現行有効範囲になければならず、スレッド可視でなければなりません。 スレッド可視変数は、次のいずれかになります。

variable_name_list を指定しないと、すべてのスレッド可視変数がメモリーへの書き込みと読み取りの対象となります。

スレッドが FLUSH ディレクティブを検出すると、スレッドは、影響を受けた変数に加えられた修正をメモリーに書き込みます。スレッドは、変数のローカル・コピーがあれば (たとえば、レジスターの中に変数のコピーがある場合など)、メモリーから変数の最新のコピーを読み取ることもします。

FLUSH ディレクティブを使用することは、チーム内のすべてのスレッドにとって必須であるわけではありません。ただし、すべてのスレッド可視レッド変数が現在のものであることを保証するために、スレッド可視変数を修正するスレッドはすべて、 FLUSH ディレクティブを使用して、メモリー内の変数の値を更新する必要があります。 FLUSH または FLUSH を暗黙指定するディレクティブの 1 つを使用しない場合は、変数の値は最新の値でないことがあります。

FLUSH はアトミックではないことに注意してください。あるディレクティブを使用して、共用ロック変数によって制御されている共用変数を FLUSH した後で、別のディレクティブを使用して、ロック変数を FLUSH する必要があります。これによって、ロック変数の前に共用変数が確実に書き込まれるようになります。

FLUSH ディレクティブが適用されるディレクティブに NOWAIT 文節を指定しない限り、次のディレクティブは FLUSH ディレクティブを暗黙指定します。

例 1: 次の例では、2 つのスレッドは、並列的に計算を実行し、計算が完了するときに同期化されます。

      PROGRAM P
      INTEGER INSYNC(0:1), IAM
 
!$OMP PARALLEL DEFAULT(PRIVATE) SHARED(INSYNC)
      IAM = OMP_GET_THREAD_NUM()
      INSYNC(IAM) = 0
!$OMP BARRIER
      CALL WORK
!$OMP FLUSH(INSYNC)
      INSYNC(IAM) = 1                        ! Each thread sets a flag
                                             ! once it has
!$OMP FLUSH(INSYNC)                          ! completed its work.
      DO WHILE (INSYNC(1-IAM) .eq. 0)        ! One thread waits for
                                             ! another to complete
!$OMP   FLUSH(INSYNC)                        ! its work.
      END DO
 
!$OMP END PARALLEL
 
      END PROGRAM P
 
      SUBROUTINE WORK                        ! Each thread does indep-
                                             ! endent calculations.
!       ...
!$OMP FLUSH                                  ! flush work variables
                                             ! before INSYNC
                                             ! is flushed.
      END SUBROUTINE WORK
 

例 2: 次の例は、スレッド可視ではない変数に FLUSH を指定しようとしているので無効です。

      FUNCTION F()
      INTEGER, AUTOMATIC :: i
!$OMP FLUSH(I)
      END FUNCTION F

MASTER / END MASTER

MASTER 構造体によって、チームのマスター・スレッドだけで実行できる、コードのブロックを定義することができます。 MASTER ディレクティブで始まり、それにコードのブロックが続き、最後は END MASTER ディレクティブで終了します。

MASTER および END MASTER ディレクティブが有効なのは、-qsmp コンパイラー・オプションが指定されているときに限られます。

構文



>>-MASTER------------------------------------------------------><
 
 
>>-block-------------------------------------------------------><
 
 
>>-END MASTER--------------------------------------------------><
 
 

block
チームのマスター・スレッドによって実行されるコードのブロックを表しています。

規則

MASTER 構造体に分岐したり、MASTER 構造体から分岐したりすることはできません。

MASTER ディレクティブは、最も近いところにある動的に対になっている PARALLEL ディレクティブがあれば、それをバインドします。

MASTER ディレクティブは、作業共用構造体の動的エクステント内、または PARALLEL DOPARALLEL SECTIONS、および PARALLEL WORKSHARE ディレクティブの動的エクステント内に指定することはできません。

MASTER 構造体に入る時、またはそこから出るときに、暗黙のバリアは存在しません。

例 1: PARALLEL ディレクティブにバインドされている MASTER ディレクティブの例です。

!$OMP PARALLEL DEFAULT(SHARED)
!$OMP MASTER
         Y = 10.0
         X =  0.0
         DO I = 1, 4
             X = X + COS(Y) + I
         END DO
!$OMP END MASTER
!$OMP BARRIER
!$OMP DO PRIVATE(J)
         DO J = 1, 10000
              A(J) = X + SIN(J*2.5)
         END DO
!$OMP END DO
!$OMP END PARALLEL
         END

関連情報

ORDERED / END ORDERED

ORDERED / END ORDERED ディレクティブ文節を使用すると、並列ループ内のコードのブロックの繰り返しが、ループが連続して実行される場合にループが実行する順序で実行されるようになります。構造体の外側のコードを並列的に実行したまま、 ORDERED 構造体の内側にあるコードを予測可能な順序で実行するよう強制することができます。

ORDERED および END ORDERED ディレクティブが有効なのは、 -qsmp コンパイラー・オプションが指定されているときに限られます。

構文



>>-ORDERED-----------------------------------------------------><
 
 
>>-block-------------------------------------------------------><
 
 
>>-END ORDERED-------------------------------------------------><
 
 

block
連続して実行されるコードのブロックを表しています。

規則

ORDERED ディレクティブは、 DO または PARALLEL DO ディレクティブの動的エクステントの中だけで使用することができます。 ORDERED 構造体に分岐したり、ORDERED 構造体から分岐したりすることはできません。

ORDERED ディレクティブは、最も近いところにある動的に対になっている DO ディレクティブまたは PARALLEL DO ディレクティブにバインドします。 ORDERED 文節は、ORDERED 構造体のバインド先となる DO ディレクティブまたは PARALLEL DO ディレクティブで指定する必要があります。

別の DO ディレクティブにバインドする ORDERED 構造体は、互いに独立しています。

ORDERED 構造体を一度に実行できるスレッドは 1 つだけです。スレッドは、ループが繰り返される順序で ORDERED 構造体に入ります。スレッドが ORDERED 構造体に入るのは、それまでのすべての繰り返しで構造体が実行されていた場合か、今後構造体が 1 度も実行されない場合です。

ORDERED 構造体のある並列ループのそれぞれの繰り返しで、 ORDERED 構造体を実行できるのは 1 度だけです。並列ループのそれぞれの繰り返しで実行できる ORDERED 構造は 1 つだけです。 ORDERED 構造体を CRITICAL 構造体の動的エクステント内で使用することはできません。

例 1: この例では、ORDERED 並列ループはカウントダウンされています。

      PROGRAM P
!$OMP PARALLEL DO ORDERED
      DO I = 3, 1, -1
!$OMP ORDERED
      PRINT *,I
!$OMP END ORDERED
      END DO
      END PROGRAM P
 

このプログラムの予期出力は、次のとおりです。

3
2
1
 

例 2: この例は、並列ループに ORDERED 構造体が 2 つあるプログラムを示しています。それぞれの繰り返しで実行できるセクションは 1 つだけです。

      PROGRAM P
!$OMP PARALLEL DO ORDERED
      DO I = 1, 3
        IF (MOD(I,2) == 0) THEN
!$OMP     ORDERED
            PRINT *, I*10
!$OMP     END ORDERED
        ELSE
!$OMP     ORDERED
            PRINT *, I
!$OMP     END ORDERED
        END IF
      END DO
      END PROGRAM P
 

このプログラムの予期出力は、次のとおりです。

1
20
3
 

例 3: この例では、プログラムは、配列のしきい値より大きいすべてのエレメントの合計数を計算します。結果が常に予測可能になるよう ORDERED が使用されています。四捨五入は、プログラムが実行されるたびに同じ順序で行われるので、結果は常に同じになります。

      PROGRAM P
        REAL :: A(1000)
        REAL :: THRESHOLD = 999.9
        REAL :: SUM = 0.0
 
!$OMP   PARALLEL DO ORDERED
        DO I = 1, 1000
          IF (A(I) > THRESHOLD) THEN
!$OMP       ORDERED
              SUM = SUM + A(I)
!$OMP       END ORDERED
          END IF
        END DO
      END PROGRAM P
 
注:
ORDERED 文節を使用しているの時にボトルネック状態にならないようにするために、チャンク・サイズの小さい DYNAMIC スケジューリングまたは STATIC スケジューリングを使用してみることができます。詳細については、 SCHEDULEを参照してください。

関連情報

PARALLEL / END PARALLEL

PARALLEL 構造体によって、スレッドのチームによって同時に実行可能なコードのブロックを定義することができます。 PARALLEL 構造体では、PARALLEL ディレクティブを使用し、それに 1 つまたは複数のコード・ブロックが続き、最後に END PARALLEL ディレクティブで終了します。

PARALLEL および END PARALLEL ディレクティブが有効なのは -qsmp コンパイラー・オプションが指定されている時に限られます。

構文



             .----------------------------.
             V                            |
>>-PARALLEL----+------------------------+-+--------------------><
               '-+---+--parallel_clause-'
                 '-,-'
 
 
>>-block-------------------------------------------------------><
 
 
>>-END PARALLEL------------------------------------------------><
 
 

parallel_clause の意味は次のとおりです。



>>-+-copyin_clause-----------------+---------------------------><
   +-default_clause----------------+
   +-firstprivate_clause-----------+
   +-IF--(--scalar_logical_expr--)-+
   +-num_threads_clause------------+
   +-private_clause----------------+
   +-reduction_clause--------------+
   '-shared_clause-----------------'
 
 

copyin_clause
COPYINを参照してください。

default_clause
DEFAULTを参照してください。

if_clause
IFを参照してください。

firstprivate_clause
FIRSTPRIVATEを参照してください。

num_threads_clause
NUM_THREADSを参照してください。

private_clause
PRIVATEを参照してください。

reduction_clause
REDUCTIONを参照してください。

shared_clause
SHAREDを参照してください。

規則

PARALLEL 構造体に分岐したり、PARALLEL 構造体から分岐したりすることはできません。

IF および DEFAULT 文節は、PARALLEL ディレクティブに 1 度だけ組み込めます。

対になっている PARALLEL 構造体の REDUCTION 文節に入っている変数は、対になっている PARALLEL 構造体内の FIRSTPRIVATELASTPRIVATE、または PRIVATE 文節に入れることはできません。さらに、内部の PARALLEL 構造体にある DEFAULT 文節を使用して PRIVATE にすることもできません。

並列領域で入出力操作を実行する時には注意が必要です。複数のスレッドが同じ装置で Fortran I/O ステートメントを実行する場合は、スレッドが同期化されるようにしなければなりません。そのようにしないと、動作は未定義になります。また、XL Fortran インプリメントでは、それぞれのスレッドは排他的に I/O 装置にアクセスしますが、OpenMP 仕様では排他的アクセスは必要ないことにも注意してください。

並列領域にバインドするディレクティブは、その並列領域に (たとえそれが逐次化されていても) バインドします。

END PARALLEL ディレクティブは、 FLUSH ディレクティブを暗黙指定します。

例 1: PARALLEL 構造体を囲む、PRIVATE 文節のある内部 PARALLEL ディレクティブの例です。注: SHARED 文節は、内部 PARALLEL 構造体に存在します。

!$OMP PARALLEL PRIVATE(X)
!$OMP DO
          DO I = 1, 10
            X(I) = I
!$OMP PARALLEL SHARED (X,Y)
!$OMP DO
      DO K = 1, 10
         Y(K,I)= K * X(I)
      END DO
!$OMP END DO
!$OMP END PARALLEL
      END DO
!$OMP END DO
!$OMP END PARALLEL

例 2: PRIVATE、および SHARED 文節の両方には変数を入れることはできないことを示す例です。

!$OMP PARALLEL PRIVATE(A), SHARED(A)
!$OMP DO
      DO I = 1, 1000
         A(I) = I * I
      END DO
!$OMP END DO
!$OMP END PARALLEL

例 3: この例は、COPYIN 文節の使用法を示しています。 PARALLEL ディレクティブによって作成されたそれぞれのスレッドには、独自の共通ブロック BLOCK のコピーがあります。 COPYIN 文節を使用すると、FCTR の初期値は、 DO ループの繰り返しを実行するスレッドの中にコピーされるようになります。

      PROGRAM TT
      COMMON /BLOCK/ FCTR
      INTEGER :: I, FCTR
!$OMP THREADPRIVATE(/BLOCK/)
      INTEGER :: A(100)
 
      FCTR = -1
      A = 0
 
!$OMP PARALLEL COPYIN(FCTR)
!$OMP DO
      DO I=1, 100
         FCTR = FCTR + I
         CALL SUB(A(I), I)
      ENDDO
!$OMP END PARALLEL
 
      PRINT *, A
      END PROGRAM
 
      SUBROUTINE SUB(AA, J)
      INTEGER :: FCTR, AA, J
      COMMON /BLOCK/ FCTR
!$OMP THREADPRIVATE(/BLOCK/)    ! EACH THREAD GETS ITS OWN COPY
                                ! OF BLOCK.
      AA = FCTR
      FCTR = FCTR - J
      END SUBROUTINE SUB

予期出力は、次のとおりです。

0 1 2 3 ... 96 97 98 99

関連情報

PARALLEL DO / END PARALLEL DO

PARALLEL DO ディレクティブでは、どのループをコンパイラーによって並列処理するかを指定できます。これは、意味上は次のものと同じです。

!$OMP   PARALLEL
!$OMP   DO
 ...
!$OMP ENDDO
!$OMP END PARALLEL

さらに、ループを並列処理するために便利な方法です。 END PARALLEL DO ディレクティブによって、PARALLEL DO ディレクティブによって指定された DO ループの終わりを示すことができます。

PARALLEL DO および END PARALLEL DO ディレクティブが有効なのは -qsmp コンパイラー・オプションが指定されている時に限られます。

構文



                .-------------------------------.
                V                               |
>>-PARALLEL DO----+---------------------------+-+--------------><
                  '-+---+--parallel_do_clause-'
                    '-,-'
 
 
>>-parallel_do_loop--------------------------------------------><
 
 
>>-+-----------------+-----------------------------------------><
   '-END PARALLEL DO-'
 
 

parallel_do_clause の意味は次のとおりです。



>>-+-copyin_clause----------------------+----------------------><
   +-default_clause---------------------+
   +-firstprivate_clause----------------+
   +-IF--(--scalar_logical_expr--)------+
   +-lastprivate_clause-----------------+
   +-num_threads_clause-----------------+
   +-ordered_clause---------------------+
   +-private_clause---------------------+
   +-reduction_clause-------------------+
   +-SCHEDULE--(--sched_type--+----+--)-+
   |                          '-,n-'    |
   '-shared_clause----------------------'
 
 

copyin_clause
COPYINを参照してください。

default_clause
DEFAULTを参照してください。

if_clause
IFを参照してください。

firstprivate_clause
FIRSTPRIVATEを参照してください。

lastprivate_clause
LASTPRIVATEを参照してください。

num_threads_clause
NUM_THREADSを参照してください。

ordered_clause
ORDEREDを参照してください。

private_clause
PRIVATEを参照してください。

reduction_clause
REDUCTIONを参照してください。

schedule_clause
SCHEDULEを参照してください。

shared_clause
SHAREDを参照してください。

規則

PARALLEL DO ディレクティブに続く最初の非注釈行は、DO ループでなければなりません。この行は、無限の DO または DO WHILE ループにすることはできません。 PARALLEL DO ディレクティブは、ディレクティブの直後にある DO ループにのみ適用され、ネストされた DO ループには適用されません。

DO ループを PARALLEL DO ディレクティブによって指定する場合、END PARALLEL DO ディレクティブは任意指定になります。 END PARALLEL DO ディレクティブを使用する場合、DO ループの直後に指定しなければなりません。

1 つの DO 構造体に、複数の DO ステートメントが入っていてもかまいません。 DO ステートメントが同じ DO 終了ステートメントを共用しており、 END PARALLEL DO ディレクティブが構造体に続いている場合は、 PARALLEL DO ディレクティブは、構造体の最外部の DO ステートメントにだけ指定できます。

PARALLEL DO ディレクティブの後に、 DO (作業共用) または DO SERIAL ディレクティブを続けることはできません。 1 つの DO ループに指定できる PARALLEL DO ディレクティブは 1 つだけです。

検出されるすべての作業共用構造体と BARRIER ディレクティブは、チーム内のすべてのスレッドによって同じ順序で検出されなければなりません。

1 つの DO ループについて、PARALLEL DO ディレクティブと INDEPENDENT ディレクティブを併用することはできません。

注:
INDEPENDENT ディレクティブを使うと、複数の HPF 処理系でコードを共有できます。複数ベンダー間の移植性を最大限に確保するには、 PARALLEL DO ディレクティブを使用しなければなりません。 PARALLEL DO ディレクティブは規定ディレクティブですが、INDEPENDENT はループの特性に関する断定ディレクティブです。 INDEPENDENT ディレクティブの詳細については、INDEPENDENT を参照してください。

IF 文節は、PARALLEL DO ディレクティブに 1 度だけ組み込めます。

IF 式は、並列構造体のコンテキストの外側で評価されます。 IF 式の中の関数参照は、副次作用を与えるものであってはなりません。

デフォルトでは、ネストされた並列ループは、IF 文節の設定にかかわりなく逐次化されます。このデフォルトは、-qsmp=nested_par コンパイラー・オプションを使用して変更できます。

内部の DO ループの REDUCTION 変数が、外側の DO ループの PRIVATE または LASTPRIVATE 文節に入れる場合、その変数は内部の DO ループの前で初期化しなければなりません。

外側の DO ループの INDEPENDENT ディレクティブの REDUCTION 文節にある変数は、PRIVATE または LASTPRIVATE 文節の data_scope_entity_list にも入れることはできません。

並列領域で入出力操作を実行する時には注意が必要です。複数のスレッドが同じ装置で Fortran I/O ステートメントを実行する場合は、スレッドが同期化されるようにしなければなりません。そのようにしないと、動作は未定義になります。また、XL Fortran インプリメントでは、それぞれのスレッドは排他的に I/O 装置にアクセスしますが、OpenMP 仕様では排他的アクセスは必要ないことにも注意してください。

並列領域にバインドするディレクティブは、その並列領域に (たとえそれが逐次化されていても) バインドします。

例 1: LASTPRIVATE 文節の有効例

!$OMP PARALLEL DO PRIVATE(I), LASTPRIVATE (X)
      DO I = 1,10
        X = I * I
        A(I) = X * B(I)
      END DO
      PRINT *, X                     ! X has the value 100

例 2: REDUCTION 文節の有効例

!$OMP PARALLEL DO PRIVATE(I), REDUCTION(+:MYSUM)
      DO I = 1, 10
        MYSUM = MYSUM + IARR(I)
      END DO

例 3: SHARED とマークされていて、複数のスレッドからアクセスされる変数を CRITICAL 構造体以外では使用できないようにする有効例。

!$OMP 	PARALLEL DO SHARED (X)
			  DO I = 1, 10
             A(I) = A(I) * I
!$OMP        CRITICAL
               X = X + A(I)
!$OMP        END CRITICAL
          END DO

例 4: END PARALLEL DO ディレクティブの有効例

         REAL A(100), B(2:100), C(100)
!$OMP PARALLEL DO
         DO I = 2, 100
             B(I) = (A(I) + A(I-1))/2.0
         END DO
!$OMP END PARALLEL DO
!$OMP PARALLEL DO
         DO  J = 1, 100
            C(J) = X + COS(J*5.5)
         END DO
!$OMP END PARALLEL DO
         END

関連情報

PARALLEL SECTIONS / END PARALLEL SECTIONS

PARALLEL SECTIONS 構造体では、コンパイラーが同時に実行できるコードの個々のブロックを定義できます。 PARALLEL SECTIONS 構造体では、PARALLEL SECTIONS ディレクティブを使用し、その後に 1 つまたは複数のコード・ブロック (SECTION ディレクティブによって区切られている) を続け、最後に END PARALLEL SECTIONS ディレクティブで終了します。

PARALLEL SECTIONSSECTION、および END PARALLEL SECTIONS ディレクティブが有効なのは、-qsmp コンパイラー・オプションが指定されている時に限られます。

構文



                      .-------------------------------------.
                      V                                     |
>>-PARALLEL SECTIONS----+---------------------------------+-+--><
                        '-+---+--parallel_sections_clause-'
                          '-,-'
 
 
                       .--------------------.
                       V                    |
>>-+---------+--block----+----------------+-+------------------><
   '-SECTION-'           '-SECTION--block-'
 
 
>>-END PARALLEL SECTIONS---------------------------------------><
 
 

parallel_sections_clause の意味は次のとおりです。



>>-+-copyin_clause-----------------+---------------------------><
   +-default_clause----------------+
   +-firstprivate_clause-----------+
   +-IF--(--scalar_logical_expr--)-+
   +-lastprivate_clause------------+
   +-num_threads_clause------------+
   +-private_clause----------------+
   +-reduction_clause--------------+
   '-shared_clause-----------------'
 
 

copyin_clause
COPYINを参照してください。

default_clause
DEFAULTを参照してください。

firstprivate_clause
FIRSTPRIVATEを参照してください。

if_clause
IFを参照してください。

lastprivate_clause
LASTPRIVATEを参照してください。

num_threads_clause
NUM_THREADSを参照してください。

private_clause
PRIVATEを参照してください。

reduction_clause
REDUCTIONを参照してください。

shared_clause
SHAREDを参照してください。

規則

PARALLEL SECTIONS 構造体には、上記の構文で示されているように、区切りディレクティブと、区切りディレクティブで囲まれているコード・ブロックが含まれます。以下の規則は、セクション にも当てはまります。セクションとは、区切りディレクティブ内にあるコード・ブロックのことです。

SECTION ディレクティブは、コード・ブロックの始まりをマークします。少なくとも 1 つの SECTION とそのコード・ブロックを PARALLEL SECTIONS 構造体に入れなければなりません。ただし、SECTION ディレクティブは、最初のセクションには指定する必要がありません。ブロックの最後は、別の SECTION ディレクティブか、または END PARALLEL SECTIONS ディレクティブによって区切られます。

PARALLEL SECTIONS 構造体は、指定のコード・セクションの並列実行を指定するために使用できます。セクションの実行順序には前提事項はありません。セクションが他のセクションを妨害することはありません。ただし、 CRITICAL 構造体内で生じる妨害は例外です。詳細については、 CRITICAL 構造体の外で発生する妨害の定義を参照してください。

PARALLEL SECTIONS 構造体によって定義されているコード・ブロックに分岐したり、そのコード・ブロックから分岐することはできません。

コンパイラーは、並列で実行されるスレッドの数とセクションの数という演算項目の数に基づいて、スレッド間で作業を分割する方法を決定します。したがって、1 つのスレッドが SECTION を複数回実行したり、 SECTION をまったく実行しないこともあります。

検出されるすべての作業共用構造体と BARRIER ディレクティブは、チーム内のすべてのスレッドによって同じ順序で検出されなければなりません。

PARALLEL SECTIONS 構造体の場合、PRIVATE 文節に入っていない変数は、デフォルトで SHARED として想定されます。

PARALLEL SECTIONS 構造体の場合、外側の DO ループの INDEPENDENT ディレクティブまたは PARALLEL DO ディレクティブの REDUCTION 文節にある変数は、 PRIVATE 文節の data_scope_entity_list にも入れることはできません。

内部 PARALLEL SECTIONS 構造体の REDUCTION 変数が、外側の DO ループまたは PARALLEL SECTIONS 構造体の PRIVATE 文節に入れる場合、その変数は内部の PARALLEL SECTIONS 構造体の前で初期化しなければなりません。

PARALLEL SECTIONS 構造体は、CRITICAL 構造体に入れることはできません。

並列領域で入出力操作を実行する時には注意が必要です。複数のスレッドが同じ装置で Fortran I/O ステートメントを実行する場合は、スレッドが同期化されるようにしなければなりません。そのようにしないと、動作は未定義になります。また、XL Fortran インプリメントでは、それぞれのスレッドは排他的に I/O 装置にアクセスしますが、OpenMP 仕様では排他的アクセスは必要ないことにも注意してください。

並列領域にバインドするディレクティブは、その並列領域に (たとえそれが逐次化されていても) バインドします。

END PARALLEL SECTIONS ディレクティブは、 FLUSH ディレクティブを暗黙指定します。

例 1:

!$OMP PARALLEL SECTIONS
!$OMP   SECTION
          DO I = 1, 10
            C(I) = MAX(A(I),A(I+1))
          END DO
!$OMP   SECTION
          W = U + V
          Z = X + Y
!$OMP END PARALLEL SECTIONS

例 2: この例では、指標変数 I が PRIVATE として宣言されています。最初の任意指定の SECTION ディレクティブが省略されていることに注意してください。

!$OMP PARALLEL SECTIONS PRIVATE(I)
          DO I = 1, 100
            A(I) = A(I) * I
          END DO
!$OMP   SECTION
          CALL NORMALIZE (B)
          DO I = 1, 100
            B(I) = B(I) + 1.0
          END DO
!$OMP   SECTION
          DO I = 1, 100
            C(I) = C(I) * C(I)
          END DO
!$OMP END PARALLEL SECTIONS

例 3: 複数セクションにまたがって変数 C にデータの依存性があるため、この例は無効です。

!$OMP PARALLEL SECTIONS
!$OMP   SECTION
          DO I = 1, 10
            C(I) = C(I) * I
          END DO
!$OMP   SECTION
          DO K = 1, 10
            D(K) = C(K) + K
          END DO
!$OMP END PARALLEL SECTIONS

関連情報

PARALLEL WORKSHARE / END PARALLEL WORKSHARE

PARALLEL WORKSHARE 構造体は、 WORKSHARE ディレクティブを PARALLEL 構造体の内部に組み込むための簡易書式メソッドを提供します。

構文



                      .--------------------------------------.
                      V                                      |
>>-PARALLELWORKSHARE----+----------------------------------+-+-><
                        '-+---+--parallel_workshare_clause-'
                          '-,-'
 
 
>>-block-------------------------------------------------------><
 
 
>>-END PARALLEL WORKSHARE--------------------------------------><
 
 

ここで parallel_workshare_clause は、 PARALLEL または WORKSHARE ディレクティブのどちらかによって受け入れられる、任意のディレクティブの文節です。

関連情報

SCHEDULE

SCHEDULE ディレクティブでは、並列化のためのチャンク方式を指定できます。スケジューリング・タイプまたはチャンク・サイズに応じて、異なる方法で作業がスレッドに割り当てられます。

SCHEDULE ディレクティブは、-qsmp オプション・コンパイラー・オプションが指定された場合にのみ有効です。

構文



>>-SCHEDULE--(--sched_type--+------+--)------------------------><
                            '-,--n-'
 
 

n
n は、正の宣言式でなければなりません。sched_type RUNTIME には、n を指定してはなりません。

sched_type
AFFINITYDYNAMICGUIDEDRUNTIME、または STATIC です。

sched_type パラメーターについて詳しくは、SCHEDULE 文節を参照してください。

number_of_iterations
並列化するループの繰り返しの回数。

number_of_threads
プログラムによって使用されるスレッドの数。

規則

SCHEDULE ディレクティブは、有効範囲単位の仕様の部分に入れなければなりません。

1 つの SCHEDULE ディレクティブだけを有効範囲単位の仕様の部分に入れることができます。

SCHEDULE ディレクティブは次のものに適用されます。

チャンク・サイズ n のために宣言式に入れる仮引き数、またはそこで参照される仮引き数は、SUBROUTINE または FUNCTION ステートメント、および指定のサブプログラムにあるすべての ENTRY ステートメントにも入れなければなりません。

指定したチャンク・サイズ n が繰り返しの数より大きい場合、ループは並列化されずに、単一スレッドで実行されます。

チャンク化のアルゴリズムを複数指定する場合、コンパイラーは次の優先順位に従います。

  1. SCHEDULE 文節から PARALLEL DO ディレクティブ。
  2. SCHEDULE ディレクティブ。
  3. -qsmp コンパイラー・オプションの schedule サブオプション。「ユーザーズ・ガイド」の『-qsmp オプション』を参照してください。
  4. XLSMPOPTS 実行時オプション。「ユーザーズ・ガイド」の『XLSMPOPTS』を参照してください。
  5. 実行時のデフォルト値 (つまり STATIC)。

例 1: 条件は次のとおりです。

number of iterations = 1000
number of threads = 4
 

GUIDED スケジューリング・タイプを使用。この場合のチャンク・サイズは次のとおりです。

250 188 141 106 79 59 45 33 25 19 14 11 8 6 4 3 3 2 1 1 1 1
 

繰り返しは次のチャンクに分割されます。

chunk  1 = iterations    1 to  250
chunk  2 = iterations  251 to  438
chunk  3 = iterations  439 to  579
chunk  4 = iterations  580 to  685
chunk  5 = iterations  686 to  764
chunk  6 = iterations  765 to  823
chunk  7 = iterations  824 to  868
chunk  8 = iterations  869 to  901
chunk  9 = iterations  902 to  926
chunk 10 = iterations  927 to  945
chunk 11 = iterations  946 to  959
chunk 12 = iterations  960 to  970
chunk 13 = iterations  971 to  978
chunk 14 = iterations  979 to  984
chunk 15 = iterations  985 to  988
chunk 16 = iterations  989 to  991
chunk 17 = iterations  992 to  994
chunk 18 = iterations  995 to  996
chunk 19 = iterations  997 to  997
chunk 20 = iterations  998 to  998
chunk 21 = iterations  999 to  999
chunk 22 = iterations 1000 to 1000
 

作業分割の一例は次のとおりです。

thread 1 executes chunks 1 5 10 13 18 20
thread 2 executes chunks 2 7  9 14 16 22
thread 3 executes chunks 3 6 12 15 19
thread 4 executes chunks 4 8 11 17 21
 

例 2: 条件は次のとおりです。

number of iterations = 100
number of threads = 4
 

AFFINITY スケジューリング・タイプを使用。この場合、繰り返しは次の区画に分割されます。

partition 1 = iterations  1 to 25
partition 2 = iterations 26 to  50
partition 3 = iterations 51 to  75
partition 4 = iterations 76 to 100
 

区画は次のチャンクに分割されます。

chunk 1a = iterations   1 to  13
chunk 1b = iterations  14 to  19
chunk 1c = iterations  20 to  22
chunk 1d = iterations  23 to  24
chunk 1e = iterations  25 to  25
 
chunk 2a = iterations  26 to  38
chunk 2b = iterations  39 to  44
chunk 2c = iterations  45 to  47
chunk 2d = iterations  48 to  49
chunk 2e = iterations  50 to  50
 
chunk 3a = iterations  51 to  63
chunk 3b = iterations  64 to  69
chunk 3c = iterations  70 to  72
chunk 3d = iterations  73 to  74
chunk 3e = iterations  75 to  75
 
chunk 4a = iterations  76 to  88
chunk 4b = iterations  89 to  94
chunk 4c = iterations  95 to  97
chunk 4d = iterations  98 to  99
chunk 4e = iterations 100 to 100
 

作業分割の一例は次のとおりです。

thread 1 executes chunks 1a 1b 1c 1d 1e 4d
thread 2 executes chunks 2a 2b 2c 2d
thread 3 executes chunks 3a 3b 3c 3d 3e 2e
thread 4 executes chunks 4a 4b 4c 4e
 

このシナリオでは、スレッド 1 がその区画内のチャンクをすべて実行し終え、スレッド 4 の区画から使用可能なチャンクを取っています。同様に、スレッド 3 はその区画内のチャンクをすべて実行し終え、スレッド 2 の区画から使用可能なチャンクを取りました。

例 3: 条件は次のとおりです。

number of iterations = 1000
number of threads = 4
 

DYNAMIC スケジューリング・タイプを使用。この場合のチャンク・サイズは次のとおりです。

100 100 100 100 100 100 100 100 100 100
 

繰り返しは次のチャンクに分割されます。

chunk  1 = iterations   1 to  100
chunk  2 = iterations 101 to  200
chunk  3 = iterations 201 to  300
chunk  4 = iterations 301 to  400
chunk  5 = iterations 401 to  500
chunk  6 = iterations 501 to  600
chunk  7 = iterations 601 to  700
chunk  8 = iterations 701 to  800
chunk  9 = iterations 801 to  900
chunk 10 = iterations 901 to 1000
 

作業分割の一例は次のとおりです。

thread 1 executes chunks 1  5  9
thread 2 executes chunks 2  8
thread 3 executes chunks 3  6  10
thread 4 executes chunks 4  7
 

例 4: 条件は次のとおりです。

number of iterations = 100
number of threads = 4
 

STATIC スケジューリング・タイプを使用。繰り返しは次のチャンクに分割されます。

chunk 1 = iterations  1 to  25
chunk 2 = iterations 26 to  50
chunk 3 = iterations 51 to  75
chunk 4 = iterations 76 to 100
 

作業分割の一例は次のとおりです。

thread 1 executes chunks 1
thread 2 executes chunks 2
thread 3 executes chunks 3
thread 4 executes chunks 4
 

関連情報

SECTIONS / END SECTIONS

SECTIONS 構造体は、チーム内のスレッドが並列で実行するコードの別個のブロックを定義しています。

SECTIONS および END SECTIONS ディレクティブが有効なのは、 -qsmp コンパイラー・オプションが指定されているときに限られます。

構文



             .----------------------------.
             V                            |
>>-SECTIONS----+------------------------+-+--------------------><
               '-+---+--sections_clause-'
                 '-,-'
 
 
                       .--------------------.
                       V                    |
>>-+---------+--block----+----------------+-+------------------><
   '-SECTION-'           '-SECTION--block-'
 
 
>>-END SECTIONS--+--------+------------------------------------><
                 '-NOWAIT-'
 
 

sections_clause の意味は次のとおりです。



>>-+-firstprivate_clause-+-------------------------------------><
   +-lastprivate_clause--+
   +-private_clause------+
   '-reduction_clause----'
 
 

firstprivate_clause
FIRSTPRIVATEを参照してください。

lastprivate_clause
LASTPRIVATEを参照してください。

private_clause
PRIVATEを参照してください。

reduction_clause
REDUCTIONを参照してください。

規則

SECTIONS 構造体は、チーム内のすべてのスレッドによって検出されるか、チーム内のどのスレッドによっても検出されないかのどちらかでなければなりません。検出されるすべての作業共用構造体と BARRIER ディレクティブは、チーム内のすべてのスレッドによって同じ順序で検出されなければなりません。

SECTIONS 構造体には、上記の構文で示されているように、区切りディレクティブと、区切りディレクティブで囲まれているコード・ブロックが含まれます。構造体の中には、コードのブロックが最低 1 つ入っていなければなりません。

SECTION ディレクティブは、最初のコード・ブロックを除いたすべてのコード・ブロックの先頭に指定する必要があります。ブロックの最後は、別の SECTION ディレクティブか、または END SECTIONS ディレクティブによって区切られます。

SECTIONS 構造体によって囲まれているコード・ブロックに分岐したり、そのコード・ブロックから分岐することはできません。すべての SECTION ディレクティブは、 SECTIONS/END SECTIONS ディレクティブ対の字句エクステントの中になければなりません。

コンパイラーは、並列で実行されるチーム内のスレッドの数とセクションの数という演算項目の数に基づいて、スレッド間で作業を分割する方法を決定します。したがって、1 つのスレッドが SECTION を複数回実行することがあります。また、SECTION がチーム内のスレッドによってまったく実行されないこともあります。

ディレクティブが並列で実行されるようにするには、 SECTIONS/END SECTIONS 対を並列領域の動的エクステント内に置く必要があります。このようにしないと、ブロックは逐次で実行されます。

SECTIONS ディレクティブに NOWAIT を指定する場合、早い時期にループの反復を完了させるスレッドは、 SECTIONS 構造体の後ろにある命令よりも先に実行されます。 NOWAIT 文節を指定しないと、それぞれのスレッドは、同じチーム内の他のすべてのスレッドが END SECTIONS ディレクティブに達するのを待ちます。 しかし、SECTIONS 構造体の最初には、暗黙指定された BARRIER はありません。

SECTIONS ディレクティブは、 CRITICAL または MASTER ディレクティブの動的エクステント内に指定することはできません。

同じ PARALLEL ディレクティブにバインドする SECTIONSDO または SINGLE ディレクティブをネストさせることはできません。

BARRIER および MASTER ディレクティブを、 SECTIONS ディレクティブの動的エクステントの中に入れることはできません。

END SECTIONS ディレクティブは、 FLUSH ディレクティブを暗黙指定します。

例 1: この例は、PARALLEL 領域内での SECTIONS 構造体の有効な使用法を示しています。

      INTEGER :: I, B(500), S, SUM
! ...
      S = 0
      SUM = 0
!$OMP PARALLEL SHARED(SUM), FIRSTPRIVATE(S)
!$OMP SECTIONS REDUCTION(+: SUM), LASTPRIVATE(I)
!$OMP SECTION
        S = FCT1(B(1::2))  ! Array B is not altered in FCT1.
        SUM = SUM + S
! ...
!$OMP SECTION
        S = FCT2(B(2::2))  ! Array B is not altered in FCT2.
        SUM = SUM + S
! ...
!$OMP SECTION
        DO I = 1, 500      ! The local copy of S is initialized
          S = S + B(I)     ! to zero.
        END DO
        SUM = SUM + S
! ...
!$OMP END SECTIONS
! ...
!$OMP DO REDUCTION(-: SUM)
      DO J=I-1, 1, -1    ! The loop starts at 500 -- the last
                         ! value from the previous loop.
        SUM = SUM - B(J)
      END DO
 
!$OMP MASTER
      SUM = SUM - FCT1(B(1::2)) - FCT2(B(2::2))
!$OMP END MASTER
!$OMP END PARALLEL
! ...
                    ! Upon termination of the PARALLEL
                    ! region, the value of SUM remains zero.

例 2: この例は、ネストされた SECTIONS の有効な使用法を示しています。

!$OMP PARALLEL
!$OMP MASTER
      CALL RANDOM_NUMBER(CX)
      CALL RANDOM_NUMBER(CY)
      CALL RANDOM_NUMBER(CZ)
!$OMP END MASTER
 
!$OMP SECTIONS
!$OMP SECTION
!$OMP   PARALLEL
!$OMP   SECTIONS PRIVATE(I)
!$OMP   SECTION
          DO I=1, 5000
            X(I) = X(I) + CX
          END DO
!$OMP   SECTION
          DO I=1, 5000
            Y(I) = Y(I) + CY
          END DO
!$OMP   END SECTIONS
!$OMP   END PARALLEL
 
!$OMP SECTION
!$OMP   PARALLEL SHARED(CZ,Z)
!$OMP   DO
        DO I=1, 5000
          Z(I) = Z(I) + CZ
        END DO
!$OMP   END DO
!$OMP   END PARALLEL
!$OMP END SECTIONS NOWAIT
 
! The following computations do not
! depend on the results from the
! previous section.
 
!$OMP DO
      DO I=1, 5000
        T(I) = T(I) * CT
      END DO
!$OMP END DO
!$OMP END PARALLEL
 

関連情報

SINGLE / END SINGLE

SINGLE / END SINGLE ディレクティブ構造体を使用して、チーム内の 1 つのスレッドだけに実行される囲まれたコードを指定することができます。

SINGLE ディレクティブが有効なのは、 -qsmp コンパイラー・オプションが指定されているときに限られます。

構文



           .--------------------------.
           V                          |
>>-SINGLE----+----------------------+-+------------------------><
             '-+---+--single_clause-'
               '-,-'
 
 
>>-block-------------------------------------------------------><
 
 
>>-END SINGLE--+-------------------+---------------------------><
               +-NOWAIT------------+
               '-end_single_clause-'
 
 

single_clause の意味は次のとおりです。



>>-+-private_clause------+-------------------------------------><
   '-firstprivate_clause-'
 
 

private_clause
PRIVATEを参照してください。

firstprivate_clause
FIRSTPRIVATEを参照してください。

end_single_clause の意味は次のとおりです。



   .---------------------------.
   V                           |
>>---copyprivate_clause--+---+-+-------------------------------><
                         '-,-'
 
 

NOWAIT

copyprivate_clause
.

規則

SINGLE 構造体の内部で囲まれているブロックに分岐したり、そのブロックから分岐したりすることはできません。

SINGLE 構造体は、チーム内のすべてのスレッドによって検出されるか、チーム内のどのスレッドによっても検出されないかのどちらかでなければなりません。検出されるすべての作業共用構造体と BARRIER ディレクティブは、チーム内のすべてのスレッドによって同じ順序で検出されなければなりません。

END SINGLE ディレクティブに NOWAIT を指定すると、 SINGLE 構造体を実行していないスレッドは、 SINGLE 構造体の後ろにある命令よりも先に実行されます。 NOWAIT 文節を指定しないと、それぞれのスレッドは、構造体を実行しているスレッドが END SINGLE ディレクティブに達するまで、 END SINGLE ディレクティブで待ちます。 同じ END SINGLE ディレクティブの中で、 NOWAIT および COPYPRIVATE を一緒に指定できません。

SINGLE 構造体の最初には、暗黙指定された BARRIER はありません。 NOWAIT 文節を指定しないと、 END SINGLE ディレクティブで BARRIER ディレクティブが暗黙指定されます。

同じ PARALLEL ディレクティブにバインドする SECTIONSDO および SINGLE ディレクティブをネストさせることはできません。

SINGLE ディレクティブを、 CRITICAL および MASTER ディレクティブの動的エクステントの中に入れることはできません。 BARRIER および MASTER ディレクティブを、 SINGLE ディレクティブの動的エクステントの中に入れることはできません。

SINGLE 構造体を囲んでいる PARALLEL 構造体の中で、変数を PRIVATEFIRSTPRIVATELASTPRIVATE または REDUCTION として指定してある場合は、同じ変数を SINGLE 構造体の PRIVATE または FIRSTPRIVATE 文節の中で指定することはできません。

SINGLE ディレクティブは、最も近いところにある動的に対になっている PARALLEL ディレクティブがあれば、それをバインドします。

例 1: この例では、SINGLE 構造体に入る前にすべてのスレッドが作業を終えるよう、 BARRIER ディレクティブが使用されています。

      REAL :: X(100), Y(50)
!     ...
!$OMP PARALLEL DEFAULT(SHARED)
      CALL WORK(X)
 
!$OMP BARRIER
!$OMP SINGLE
      CALL OUTPUT(X)
      CALL INPUT(Y)
!$OMP END SINGLE
 
      CALL WORK(Y)
!$OMP END PARALLEL
 

例 2: この例では、SINGLE 構造体があるので、コード・ブロックを実行するスレッドは 1 つだけになります。このケースでは、配列 BDO (作業共用) 構造体の中で初期化されています。初期化後に、合計を出すために 1 つのスレッドが使用されています。

      INTEGER :: I, J
      REAL :: B(500,500), SM
!     ...
 
      J = ...
      SM = 0.0
!$OMP PARALLEL
!$OMP DO PRIVATE(I)
      DO I=1, 500
        CALL INITARR(B(I,:), I)       ! initialize the array B
      ENDDO
!$OMP END DO
 
!$OMP SINGLE                          ! employ only one thread
      DO I=1, 500
        SM = SM + SUM(B(J:J+1,I))
      ENDDO
!$OMP END SINGLE
 
!$OMP DO PRIVATE(I)
      DO I=500, 1, -1
        CALL INITARR(B(I,:), 501-I)   ! re-initialize the array B
      ENDDO
!$OMP END PARALLEL
 

例 3: この例は、PRIVATE 文節の有効な使用法を示しています。配列 X は、SINGLE 構造体に対して PRIVATE になっています。構造体のすぐ後に続く配列 X を参照する場合、これは未定義になります。

      REAL :: X(2000), A(1000), B(1000)
 
!$OMP PARALLEL
!     ...
!$OMP SINGLE PRIVATE(X)
      CALL READ_IN_DATA(X)
      A = X(1::2)
      B = X(2::2)
!$OMP END SINGLE
!     ...
!$OMP END PARALLEL
 

例 4: この例では、TMP を割り振る際に LASTPRIVATE 変数 I が使用されており、 SINGLE 構造体の中で PRIVATE 変数が使用されています。

      SUBROUTINE ADD(A, UPPERBOUND)
        INTEGER :: A(UPPERBOUND), I, UPPERBOUND
        INTEGER, ALLOCATABLE :: TMP(:)
!  ...
!$OMP   PARALLEL
!$OMP   DO LASTPRIVATE(I)
        DO I=1, UPPERBOUND
          A(I) = I + 1
        ENDDO
!$OMP   END DO
 
!$OMP   SINGLE FIRSTPRIVATE(I), PRIVATE(TMP)
        ALLOCATE(TMP(0:I-1))
        TMP = (/ (A(J),J=I,1,-1) /)
!  ...
        DEALLOCATE(TMP)
!$OMP   END SINGLE
!$OMP   END PARALLEL
!  ...
      END SUBROUTINE ADD
 

例 5: この例では、変数 I の値をユーザーが入力します。次に、この値は、END SINGLE ディレクティブの COPYPRIVATE 文節を使用して、チーム内の他のすべてのスレッドで、対応する変数 I にコピーされます。

        INTEGER I
  !$OMP PARALLEL PRIVATE (I)
  !     ...
  !$OMP SINGLE
        READ (*, *) I
  !$OMP END SINGLE COPYPRIVATE (I)   ! In all threads in the team, I
                                     ! is equal to the value
  !     ...                          ! that you entered.
  !$OMP END PARALLEL

例 6: この例では、POINTER 属性を持つ変数 J が、 END SINGLE ディレクティブ上の COPYPRIVATE 文節に指定されています。 J の値 (それが指しているオブジェクトの値ではありません) は、同じチーム内の他のすべてのスレッドで、対応する変数 J にコピーされます。オブジェクト自体は、チーム内のすべてのスレッド間で共用されます。

        INTEGER, POINTER :: J
  !$OMP PARALLEL PRIVATE (J)
  ! ...
  !$OMP SINGLE
        ALLOCATE (J)
        READ (*, *) J
  !$OMP END SINGLE COPYPRIVATE (J)
  !$OMP ATOMIC
        J = J + OMP_GET_THREAD_NUM()
  !$OMP BARRIER
  !$OMP SINGLE
        WRITE (*, *) 'J = ', J   ! The result is the sum of all values added to
                                 ! J. This result shows that the pointer object
                                 ! is shared by all threads in the team.
        DEALLOCATE (J)
  !$OMP END SINGLE
  !$OMP END PARALLEL
 

関連情報

THREADLOCAL

THREADLOCAL ディレクティブは、スレッド固有の共通データを宣言するときに使用します。これは、COMMON ブロック内のデータへのアクセスを逐次化する方法にもなります。

このディレクティブを利用するために -qsmp コンパイラー・オプションを利用する必要はありませんが、必要なライブラリーにリンクするための呼び出しコマンドは xlf_rxlf_r7xlf90_rxlf90_r7xlf95_r、または xlf95_r7 でなければなりません。

構文



                        .-,-----------------------.
                        V                         |
>>-THREADLOCAL--+----+----/--common_block_name--/-+------------><
                '-::-'
 
 

規則

名前付きブロックだけを THREADLOCAL で宣言できます。通常、名前付き共通ブロックに適用される規則および制約はすべて THREADLOCAL で宣言されている共通ブロックに適用されます。名前付き共通ブロックに適用される規則と制約の詳細については、COMMONを参照してください。

THREADLOCAL ディレクティブは、有効範囲単位の specification_part に入れなければなりません。共通ブロックを THREADLOCAL ディレクティブに入れる場合、同じ有効範囲単位の COMMON ステートメントにもこの共通ブロックを宣言しなければなりません。 THREADLOCAL ディレクティブは、COMMON ステートメントの前にも後にも入れることができます。有効範囲単位の specification_part の詳細については、メインプログラムを参照してください。

共通ブロックが PURE サブプログラムに宣言されている場合、共通ブロックに THREADLOCAL 属性を指定することはできません。

THREADLOCAL 共通ブロックのメンバーを NAMELIST ステートメントに入れることはできません。

使用関連付けがある共通ブロックは、USE ステートメントを含む有効範囲単位内の THREADLOCAL として宣言することはできません。

THREADLOCAL 共通ブロック内で宣言されているポインターは、 -qinit=f90ptr コンパイラー・オプションの影響を受けません。

THREADLOCAL 共通ブロック内にあるオブジェクトは、並列ループと並列セクションで使用できます。しかし、これらのオブジェクトはループの繰り返し間、および並列セクションのコード・ブロック間で暗黙的に共用されます。つまり、有効範囲単位内では、すべてのアクセス可能共通ブロック (THREADLOCAL として宣言されていてもいなくても) は、その有効範囲単位の並列ループと並列セクションに SHARED 属性があるということです。

共通ブロックが有効範囲単位内で THREADLOCAL として宣言される場合、その共通ブロックを宣言または参照しており、直接または間接的に有効範囲単位によって参照されているサブプログラムは、その有効範囲単位を実行している同一のスレッドによって実行しなければなりません。共通ブロックを宣言する 2 つのプロシージャーが異なるスレッドによって実行されると、共通ブロックに THREADLOCAL が宣言されるなら、それらのプロシージャーは異なる共通ブロックのコピーを得ることになります。スレッドは、以下のいずれかの方法で作成できます。

共通ブロックを 1 つの有効範囲単位内の THREADLOCAL として宣言する場合、その共通ブロックは、共通ブロックを宣言する各有効範囲単位ごとに THREADLOCAL として宣言しなければなりません。

SAVE 属性がない THREADLOCAL 共通ブロックをサブプログラム内で宣言する場合、ブロックのメンバーはサブプログラムの RETURN または END で未定義になります。ただし、直接または間接にサブプログラムを参照している共通ブロックにアクセスできる有効範囲単位がほかに 1 つ以上ある場合はこの限りではありません。

THREADLOCAL ディレクティブと THREADPRIVATE ディレクティブの両方に、同じ common_block_name を指定することはできません。

例 1: 次のプロシージャー "FORT_SUB" は、2 つのスレッドによって呼び出されます。

SUBROUTINE FORT_SUB(IARG)
  INTEGER IARG
 
  CALL LIBRARY_ROUTINE1()
  CALL LIBRARY_ROUTINE2()
  ...
END SUBROUTINE FORT_SUB
 

SUBROUTINE LIBRARY_ROUTINE1()
  COMMON /BLOCK/ R               ! The SAVE attribute is required for the
  SAVE /BLOCK/                   ! common block because the program requires
                                 ! that the block remain defined after
  !IBM* THREADLOCAL /BLOCK/      ! library_routine1 is invoked.
    R = 1.0
    ...
END SUBROUTINE LIBRARY_ROUTINE1
 

SUBROUTINE LIBRARY_ROUTINE2()
  COMMON /BLOCK/ R
  SAVE /BLOCK/
  !IBM* THREADLOCAL /BLOCK/
 
  ... = R
  ...
END SUBROUTINE LIBRARY_ROUTINE2

例 2: "FORT_SUB" が複数のスレッドによって呼び出されます。 "FORT_SUB" と "ANOTHER_SUB" は両方とも /BLOCK/ を THREADLOCAL として宣言するため、これは無効な例です。これらは、共通ブロックを共有しようとしますが、異なるスレッドによって実行されます。

SUBROUTINE FORT_SUB()
  COMMON /BLOCK/ J
  INTEGER :: J
  !IBM* THREADLOCAL /BLOCK/        ! Each thread executing FORT_SUB
                                   ! obtains its own copy of /BLOCK/
  INTEGER A(10)
 
  ...
  !IBM* INDEPENDENT
  DO INDEX = 1,10
    CALL ANOTHER_SUB(A(I))
  END DO
  ...
 
END SUBROUTINE FORT_SUB
 

SUBROUTINE ANOTHER_SUB(AA)         ! Multiple threads
are used to execute ANOTHER_SUB
  INTEGER AA
  COMMON /BLOCK/ J                 ! Each thread obtains a new copy of the
  INTEGER :: J                     !  common block /BLOCK/
  !IBM* THREADLOCAL /BLOCK/
  ...
  AA = J                           ! The value of 'J' is undefined.
END SUBROUTINE ANOTHER_SUB

関連情報

THREADPRIVATE

THREADPRIVATE ディレクティブを使用すると、あるスレッドに対してはプライベートとして、ただしそのスレッド内ではグローバルとして、名前付き共通ブロックまたは名前付き変数を指定できます。共通ブロックまたは変数 THREADPRIVATE を宣言すると、チーム内の各スレッドは、共通ブロックまたは変数の別個のコピーを維持します。THREADPRIVATE 共通ブロックまたは変数に書き込まれたデータは、そのスレッドに対してプライベートのままであり、チーム内の他のスレッドに対して可視ではありません。

プログラムの逐次セクションと MASTER セクションでは、マスター・スレッドが持つ名前付き共通ブロックと変数のコピーだけがアクセス可能になります。

PARALLELPARALLEL DOPARALLEL SECTIONS または PARALLEL WORKSHARE ディレクティブで COPYIN 文節を使用して、並列領域に入るときに、マスター・スレッドが持つ名前付き共通ブロックまたは名前付き変数のコピーの中のデータが、それぞれのスレッドが持つ共通ブロックまたは変数のプライベート・コピーにコピーされるよう指定します。

THREADPRIVATE ディレクティブが有効なのは、 -qsmp コンパイラー・オプションが指定されているときに限られます。

構文



>>-THREADPRIVATE--(--threadprivate_entity_list--)--------------><
 
 

threadprivate_entity_list の意味は次のとおりです。

>>-+-variable_name---------+-----------------------------------><
   '-/ common_block_name /-'
 
 

common_block_name
スレッドに対してプライベートにされる共通ブロックの名前です。

variable_name
スレッドに対してプライベートにされる変数の名前です。

規則

THREADPRIVATE 変数または共通ブロックを指定したり、 PRIVATEFIRSTPRIVATELASTPRIVATESHARED、または REDUCTION 文節の中でこの共通ブロックを構成する変数を指定することはできません。

THREADPRIVATE 変数は、SAVE 属性を持つ必要があります。モジュールの有効範囲内に宣言された変数または共通ブロックの場合は、 SAVE 属性が暗黙のうちに示されています。モジュールの有効範囲外の変数を宣言する場合は、 SAVE 属性を指定する必要があります。

THREADPRIVATE ディレクティブの中で指定できるのは、名前付き変数および名前付き共通ブロックだけです。

変数は、変数が宣言されている有効範囲内の THREADPRIVATE ディレクティブでのみ使用でき、 THREADPRIVATE 変数または共通ブロックは、特定の有効範囲内で一度だけ指定することができます。変数は、共通ブロックのエレメントであったり、 EQUIVALENCE ステートメントに宣言したりすることはできません。

THREADPRIVATE ディレクティブと THREADLOCAL ディレクティブの両方に、同じ common_block_name を指定することはできません。

名前付き共通ブロックに適用されるすべての規則と制約も、 THREADPRIVATE で宣言されている共通ブロックに適用されます。 COMMONを参照してください。

ある有効範囲単位内で共通ブロックを THREADPRIVATE として宣言すると、その共通ブロックが宣言されている他のすべての有効範囲単位内でも、この共通ブロックを THREADPRIVATE として宣言しなければなりません。

並列領域に入るときには、THREADPRIVATE 変数、または、 THREADPRIVATE 共通ブロック内の変数は、COPYIN 文節内に宣言されるとき、次の基準に従います。

プログラムの最初の並列領域に入る際は、 COPYIN 文節に指定されていない、 THREADPRIVATE 変数または THREADPRIVATE 共通ブロック内の変数は、以下の基準に従います。

プログラムの後続の並列領域に入る際は、 COPYIN 文節に指定されていない、 THREADPRIVATE 変数または THREADPRIVATE 共通ブロック内の変数は、以下の基準に従います。

共通ブロックの名前には、使用関連付けまたはホスト関連付けによってアクセスすることはできません。したがって、THREADPRIVATE ディレクティブを構成している有効範囲単位内で共通ブロックが宣言されている場合、名前付き共通ブロックを使用できるのは、 THREADPRIVATE ディレクティブの中だけです。ただし、共通ブロックの変数には、使用関連付けまたはホスト関連付けによってアクセスすることができます。詳細については、ホスト関連付け使用関連付けを参照してください。

-qinit=f90ptr コンパイラー・オプションは、 THREADPRIVATE 共通ブロックの中で宣言したポインターに影響を与えることはありません。

DEFAULT 文節は、THREADPRIVATE 共通ブロックの中の変数に影響を与えることはありません。

例 1: この例では、PARALLEL DO ディレクティブは、 SUB1 を呼び出す複数のスレッドを呼び出しています。 SUB1 の中の共通ブロック BLK は、 SUB1 によって呼び出されるサブルーチン SUB2 を持つスレッドに固有のデータを共用しています。

      PROGRAM TT
        INTEGER :: I, B(50)
 
!$OMP   PARALLEL DO SCHEDULE(STATIC, 10)
        DO I=1, 50
          CALL SUB1(I, B(I))       ! Multiple threads call SUB1.
        ENDDO
      END PROGRAM TT
 
      SUBROUTINE SUB1(J, X)
        INTEGER :: J, X, A(100)
        COMMON /BLK/ A
!$OMP   THREADPRIVATE(/BLK/)   ! Array a is private to each thread.
!  ...
        CALL SUB2(J)
        X = A(J) + A(J + 50)
!  ...
      END SUBROUTINE SUB1
 
      SUBROUTINE SUB2(K)
        INTEGER :: C(100)
        COMMON /BLK/ C
!$OMP   THREADPRIVATE(/BLK/)
!  ...
        C = K
!  ...                       ! Since each thread has its own copy of
                             ! common block BLK, the assignment of
                             ! array C has no effect on the copies of
                             ! that block owned by other threads.
END SUBROUTINE SUB2

例 2: この例では、それぞれのスレッドは並列セクションの中で、共通ブロック ARR の独自のコピーを持っています。あるスレッドが共通ブロック変数 TEMP を初期化する場合、初期値は他のスレッドに可視ではありません。

      PROGRAM ABC
        INTEGER :: I, TEMP(100), ARR1(50), ARR2(50)
        COMMON /ARR/ TEMP
!$OMP   THREADPRIVATE(/ARR/)
        INTERFACE
          SUBROUTINE SUBS(X)
            INTEGER :: X(:)
          END SUBROUTINE
        END INTERFACE
! ...
!$OMP   PARALLEL SECTIONS
!$OMP   SECTION                   ! The thread has its own copy of the
! ...                             ! common block ARR.
          TEMP(1:100:2) = -1
          TEMP(2:100:2) = 2
          CALL SUBS(ARR1)
! ...
!$OMP   SECTION                   ! The thread has its own copy of the
! ...                             ! common block ARR.
          TEMP(1:100:2) = 1
          TEMP(2:100:2) = -2
          CALL SUBS(ARR2)
! ...
!$OMP    END PARALLEL SECTIONS
! ...
        PRINT *, SUM(ARR1), SUM(ARR2)
      END PROGRAM ABC
 
      SUBROUTINE SUBS(X)
        INTEGER :: K, X(:), TEMP(100)
        COMMON /ARR/ TEMP
!$OMP   THREADPRIVATE(/ARR/)
!  ...
        DO K = 1, UBOUND(X, 1)
          X(K) = TEMP(K) + TEMP(K + 1)    ! The thread is accessing its
                                          ! own copy of
                                          ! the common block.
        ENDDO
! ...
      END SUBROUTINE SUBS

このプログラムの予期出力は、次のとおりです。

50 -50

例 3: 次の例では、共通ブロックの外側にあるローカル変数は、 THREADPRIVATE で宣言されます。

      MODULE MDL
        INTEGER          :: A(2)
        INTEGER, POINTER :: P
        INTEGER, TARGET  :: T
!$OMP THREADPRIVATE(A, P)
      END MODULE MDL
 
 
      PROGRAM MVAR
      USE MDL
 
      INTEGER :: I
      INTEGER OMP_GET_THREAD_NUM
 
      CALL OMP_SET_NUM_THREADS(2)
      A = (/1, 2/)
      T = 4
      P => T
 
!$OMP PARALLEL PRIVATE(I) COPYIN(A, P)
      I = OMP_GET_THREAD_NUM()
      IF (I .EQ. 0) THEN
        A(1) = 100
        T = 5
      ELSE IF (I .EQ. 1) THEN
        A(2) = 200
      END IF
!$OMP END PARALLEL
 
!$OMP PARALLEL PRIVATE(I)
      I = OMP_GET_THREAD_NUM()
      IF (I .EQ. 0) THEN
        PRINT *, 'A(2) = ', A(2)
      ELSE IF (I .EQ. 1) THEN
        PRINT *, 'A(1) = ', A(1)
        PRINT *, 'P => ', P
      END IF
!$OMP END PARALLEL
 
      END PROGRAM MVAR
 

動的スレッドのメカニズムが使用不可の場合は、予期される出力は次のようになります。

A(2) = 2
A(1) = 1
P => 5
または
A(1) = 1
P => 5
A(2) = 2

関連情報

WORKSHARE

WORKSHARE ディレクティブを使用すると、配列操作を並行して実行できます。 WORKSHARE ディレクティブは、囲まれたコード・ブロックに関連したタスクを、 作業単位 に分割します。スレッドのチームが WORKSHARE ディレクティブを検出すると、チーム内のスレッドはタスクを共用し、各作業単位 を正確に一度実行します。

WORKSHARE ディレクティブが有効なのは、 -qsmp コンパイラー・オプションが指定されているときに限られます。

構文



>>-WORKSHARE---------------------------------------------------><
 
 
>>-block-------------------------------------------------------><
 
 
>>-END WORKSHARE--+--------+-----------------------------------><
                  '-NOWAIT-'
 
 

block
ステートメントの構造化ブロック。これは、WORKSHARE 構造体の字句エクステント内での作業共用を可能にします。ステートメントの実行は同期化されるので、その結果が別のステートメントに従属しているステートメントは、結果が要求される前に評価されます。block には、以下のいずれかを含むことができます。

配列操作の一部として使用できる変形可能組み込み関数は、以下のとおりです。


ALL
ANY
COUNT
CSHIFT
DOT_PRODUCT
EOSHIFT

MATMUL
MAXLOC
MAXVAL
MINLOC
MINVAL
PACK

PRODUCT
RESHAPE
SPREAD
SUM
TRANSPOSE
UNPACK

block には、字句的に囲まれた PARALLEL 構造体にバインドされたステートメントを含むこともできます。これらのステートメントには制限はありません。

block 内のユーザー定義の関数呼び出しはいずれも、エレメント型である必要があります。

WORKSHARE ディレクティブ内に囲まれたステートメントは、 作業単位 に分割されます。作業単位 の定義は、評価されるステートメントによって異なります。 作業単位 は、以下のように定義されます。

上記の定義のうち、どれもブロック内のステートメントに適用されない場合は、そのステートメントが 1 つの作業単位 になります。

規則

WORKSHARE 構造体内のステートメントを確実に並行で実行するために、構造体は、並列領域の動的エクステント内に囲まなければなりません。並列領域の動的エクステントの外側で WORKSHARE 構造体を見つけたスレッドは、その構造体内でステートメントを逐次評価します。

WORKSHARE ディレクティブは、最も近いところにある動的に囲まれた PARALLEL ディレクティブがあれば、それをバインドします。

同じ PARALLEL ディレクティブとバインドする、 DOSECTIONSSINGLE および WORKSHARE ディレクティブをネストできません。

CRITICALMASTER、または ORDERED ディレクティブの動的エクステント内には、 WORKSHARE ディレクティブを指定できません。

WORKSHARE 構造体の動的エクステント内には、 BARRIERMASTER、または ORDERED ディレクティブを指定できません。

配列割り当て、スカラー割り当て、マスクされた配列割り当て、または block 内のプライベート変数に割り当てる FORALL 割り当ての場合は、結果は未定義です。

block 内の配列式が値を参照する場合は、プライベート変数の関連付け状況または割り振り状況は、各スレッドが同じ値を計算するまで、式の値は未定義です。

NO WAIT 文節を WORKSHARE 構造体の最後で指定しないと、 BARRIER ディレクティブが暗黙的に指定されます。

WORKSHARE 構造体は、チーム内のすべてのスレッドで見つかるか、まったくないかのどちらかである必要があります。

例 1: 次の例では、WORKSHARE ディレクティブが、マスクされた式を並列に評価します。

!$OMP WORKSHARE
      FORALL (I = 1 : N, AA(1, I) = 0) AA(1, I) = I
      BB = TRANSPOSE(AA)
      CC = MATMUL(AA, BB)
!$OMP ATOMIC
      S = S + SUM(CC)
!$OMP END WORKSHARE 

例 2: 次の例には、WORKSHARE 構造体の一部として、ユーザー定義の ELEMENTAL が含まれます。

!$OMP WORKSHARE
      WHERE (AA(1, :) /= 0.0) AA(1, :) = 1 / AA(1, :)
      DD = TRANS(AA(1, :))
!$OMP END WORKSHARE 
      ELEMENTAL REAL FUNCTION TRANS(ELM) RESULT(RES)
      REAL, INTENT(IN) :: ELM
      RES = ELM * ELM + 4
      END FUNCTION

関連情報


[ ページのトップ | 前ページ | 次ページ | 目次 | 索引 ]