次の節は、XL Fortran でサポートされているすべての SMP ディレクティブをアルファベット順にリストしています。 ディレクティブ文節については、SMP ディレクティブ文節を 参照してください。
目的
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--)-' |
規則
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: 次の例は無効です。 expression は update_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 ディレクティブが有効なのは、-qsmp コンパイラー・オプションが指定されているときに限られます。
構文
>>-BARRIER----------------------------------------------------->< |
規則
BARRIER ディレクティブは、最も近いところにある 動的に対になっている PARALLEL ディレクティブがあれば、 それをバインドします。
BARRIER ディレクティブは、CRITICAL、DO (作業共用)、MASTER、PARALLEL DO、PARALLEL SECTIONS、SECTIONS、SINGLE、 および 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 構文では、一度に最大 1 つの スレッドによって実行されるコードの独立したブロックを定義できます。 CRITICAL 構文には、CRITICAL ディレクティブを入れ、その後にコードのブロックを続けて、 最後は END CRITICAL ディレクティブで終了します。
型
CRITICAL および END CRITICAL ディレクティブが有効なのは、-qsmp コンパイラー・オプションが 指定されているときに限られます。
構文
>>-CRITICAL--+-----------------+------------------------------->< '-(--lock_name--)-' >>-block------------------------------------------------------->< >>-END CRITICAL--+-----------------+--------------------------->< '-(--lock_name--)-' |
規則
任意指定の lock_name は、グローバルに適用される名前です。 同じ実行可能プログラム内の他のグローバル・エンティティーを 識別するために、lock_name を使用することはできません。
lock_name が CRITICAL ディレクティブに指定されている場合、 同じ 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 コンパイラー・オプションを使用すると、 デッドロックを避けることができます。詳細については、「XL Fortran ユーザーズ・ガイド」を参照してください。
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 (作業共用) ディレクティブで 指定した 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-----' |
規則
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 ループを並列処理しないように コンパイラーに指示します。 このディレクティブは、特定の DO ループの 自動並列化をブロックするときに便利です。 DO SERIAL ディレクティブが有効なのは、 -qsmp コンパイラー・オプションが 指定されているときに限られます。
構文
>>-DO SERIAL--------------------------------------------------->< |
規則
DO SERIAL ディレクティブに続く 最初の非コメント行 (他のディレクティブは含まない) は、 DO ループでなければなりません。 DO SERIAL ディレクティブは、 ディレクティブの直後にある DO ループにのみ適用され、 ループ内でネストされているループには適用されません。
特定の DO ループに指定できる DO SERIAL ディレクティブは 1 つだけです。 DO SERIAL ディレクティブは、DO または PARALLEL DO ディレクティブとともに 同一の DO ループに指定することはできません。
DO と SERIAL
このディレクティブとともに 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 ディレクティブが有効なのは、-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 構文によって、チームのマスター・スレッドだけで 実行できる、コードのブロックを定義することができます。 MASTER ディレクティブで始まり、それにコードのブロックが続き、最後は END MASTER ディレクティブで終了します。
型
MASTER および END MASTER ディレクティブが 有効なのは、-qsmp コンパイラー・オプションが 指定されているときに限られます。
構文
>>-MASTER------------------------------------------------------>< >>-block------------------------------------------------------->< >>-END MASTER-------------------------------------------------->< |
規則
MASTER 構文に分岐したり、MASTER 構文から 分岐したりすることはできません。
MASTER ディレクティブは、最も近いところにある 動的に対になっている PARALLEL ディレクティブがあれば、 それをバインドします。
MASTER ディレクティブは、作業共用構文の動的エクステント内、または PARALLEL DO、 PARALLEL 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 構文の内側にあるコードを予測可能な順序で実行するよう 強制することができます。
ORDERED および END ORDERED ディレクティブが有効なのは、 -qsmp コンパイラー・オプションが指定されているときに限られます。
構文
>>-ORDERED----------------------------------------------------->< >>-block------------------------------------------------------->< >>-END ORDERED------------------------------------------------->< |
規則
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
関連情報
目的
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-----------------'
規則
PARALLEL 構文に分岐したり、PARALLEL 構文から 分岐したりすることはできません。
IF および DEFAULT 文節は、PARALLEL ディレクティブ に 1 度だけ組み込めます。
並列領域で入出力操作を実行する時には注意が必要です。 複数のスレッドが同じ装置で 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 ディレクティブでは、 どのループをコンパイラーによって並列処理するかを指定できます。 これは、意味上は次のものと同じです。
!$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----------------------'
規則
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 ディレクティブを 続けることはできません。 指定 DO ループに指定できる PARALLEL DO ディレクティブは 1 つだけです。
検出されるすべての作業共用構造と BARRIER ディレクティブは、 チーム内のすべてのスレッドによって同じ順序で検出されなければなりません。
1 つの DO ループについて、PARALLEL DO ディレクティブ と INDEPENDENT ディレクティブを併用することはできません。
IF 文節は、PARALLEL DO ディレクティブに 1 度だけ組み込めます。
IF 式は、並列構文のコンテキストの外側で評価されます。 IF 式の中の関数参照は、副次作用を与えるものであってはなりません。
デフォルトでは、ネストされた並列ループは、IF 文節の 設定にかかわりなく逐次化されます。 このデフォルトは、-qsmp=nested_par コンパイラー・オプションを 使用して変更できます。
内部の DO ループの REDUCTION 変数が、外側の DO ループまたは PARALLEL SECTIONS 構造体の 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 構文では、 コンパイラーが同時に実行できるコードの個々のブロックを定義できます。 PARALLEL SECTIONS 構文では、PARALLEL SECTIONS ディレクティブを 使用し、その後に 1 つまたは複数のコード・ブロック (SECTION ディレクティブによって区切られている) を続け、 最後に END PARALLEL SECTIONS ディレクティブで終了します。
PARALLEL SECTIONS、SECTION、 および 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-----------------'
規則
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 構文は、 WORKSHARE ディレクティブを PARALLEL 構文の内部に組み込むための簡易書式メソッドを提供します。
構文
.--------------------------------------. V | >>-PARALLELWORKSHARE----+----------------------------------+-+->< '-+---+--parallel_workshare_clause-' '-,-' >>-block------------------------------------------------------->< >>-END PARALLEL WORKSHARE-------------------------------------->< |
ここで parallel_workshare_clause は、 PARALLEL または WORKSHARE ディレクティブのどちらかによって受け入れられる、 任意のディレクティブの文節です。
関連情報
目的
SCHEDULE ディレクティブでは、並列化のためのチャンク方式を指定できます。 スケジューリング型またはチャンク・サイズに応じて、 異なる方法で作業がスレッドに割り当てられます。
SCHEDULE ディレクティブは、-qsmp オプション・コンパイラー・オプションが 指定された場合にのみ有効です。
構文
>>-SCHEDULE--(--sched_type--+------+--)------------------------>< '-,--n-'
sched_type パラメーターについて詳しくは、SCHEDULE 文節を 参照してください。
規則
SCHEDULE ディレクティブは、有効範囲単位の仕様の部分に入れなければなりません。
1 つの SCHEDULE ディレクティブだけを有効範囲単位の仕様の部分に入れることができます。
SCHEDULE ディレクティブは次のものに適用されます。
チャンク・サイズ n のために 宣言式に入れる仮引き数、またはそこで参照される仮引き数は、SUBROUTINE または FUNCTION ステートメント、および指定のサブプログラムにある すべての ENTRY ステートメントにも入れなければなりません。
指定したチャンク・サイズ n が繰り返しの数より大きい場合、 ループは並列化されずに、単一スレッドで実行されます。
チャンク化のアルゴリズムの決定方法を複数指定する場合、コンパイラーは 次の優先順位に従います。
例
例 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 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 構文は、チーム内のスレッドが並列で実行するコードの 別個のブロックを定義しています。
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----'
規則
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 ディレクティブにバインドする SECTIONS、 DO または 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 ディレクティブ構文を使用して、 チーム内の 1 つのスレッドだけに実行される囲まれたコードを 指定することができます。
SINGLE ディレクティブが有効なのは、 -qsmp コンパイラー・オプションが指定されているときに限られます。
構文
.--------------------------. V | >>-SINGLE----+----------------------+-+------------------------>< '-+---+--single_clause-' '-,-' >>-block------------------------------------------------------->< >>-END SINGLE--+-------------------+--------------------------->< +-NOWAIT------------+ '-end_single_clause-' |
single_clause の意味は次のとおりです。
>>-+-private_clause------+------------------------------------->< '-firstprivate_clause-'
end_single_clause の意味は次のとおりです。
.---------------------------. V | >>---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 ディレクティブにバインドする SECTIONS、 DO および SINGLE ディレクティブをネストさせることはできません。
SINGLE ディレクティブを、 CRITICAL および MASTER ディレクティブの動的エクステントの 中に入れることはできません。 BARRIER および MASTER ディレクティブを、 SINGLE ディレクティブの動的エクステントの中に入れることはできません。
SINGLE 構文を囲んでいる PARALLEL 構文の中で、 変数を PRIVATE、FIRSTPRIVATE、 LASTPRIVATE または 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 つだけになります。 このケースでは、配列 B は DO (作業共用) 構文の中で 初期化されています。 初期化後に、合計を出すために 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 ディレクティブは、 スレッド固有の共通データを宣言するときに使用します。 これは、COMMON ブロック内のデータへのアクセスを逐次化する方法にもなります。
このディレクティブを利用するために -qsmp コンパイラー・オプションを利用する必要はありませんが、必要な ライブラリーにリンクするための呼び出しコマンドは xlf_r、xlf90_r、 または xlf95_r でなければなりません。
構文
.-,-----------------------. 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 共通ブロックまたは変数に書き込まれたデータは、 そのスレッドに対してプライベートのままであり、チーム内の他のスレッドに対して可視ではありません。
プログラムの逐次セクションと MASTER セクションでは、 マスター・スレッドが持つ名前付き共通ブロックと変数のコピーだけがアクセス可能になります。
PARALLEL、PARALLEL DO、 PARALLEL SECTIONS または PARALLEL WORKSHARE ディレクティブで COPYIN 文節を使用して、 並列領域に入るときに、マスター・スレッドが持つ名前付き共通ブロックまたは名前付き変数のコピーの中のデータが、それぞれのスレッドが持つ共通ブロックまたは変数のプライベート・コピーにコピーされるよう指定します。
THREADPRIVATE ディレクティブが有効なのは、 -qsmp コンパイラー・オプションが指定されているときに限られます。
構文
>>-THREADPRIVATE--(--threadprivate_entity_list--)-------------->< threadprivate_entity_list の意味は次のとおりです。 >>-+-variable_name---------+----------------------------------->< '-/ common_block_name /-' |
規則
THREADPRIVATE 変数または共通ブロックを指定したり、 PRIVATE、FIRSTPRIVATE、LASTPRIVATE、 SHARED、または 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 ディレクティブが有効なのは、 -qsmp コンパイラー・オプションが指定されているときに限られます。
構文
>>-WORKSHARE--------------------------------------------------->< >>-block------------------------------------------------------->< >>-END WORKSHARE--+--------+----------------------------------->< '-NOWAIT-' |
配列操作の一部として使用できる変形可能組み込み関数は、以下のとおりです。
|
|
|
block には、字句的に囲まれた PARALLEL 構文にバインドされた ステートメントを含むこともできます。 これらのステートメントには制限はありません。
block 内のユーザー定義の関数呼び出しはいずれも、エレメント型である必要があります。
WORKSHARE ディレクティブ内に囲まれたステートメントは、作業単位 に分割されます。 作業単位 の定義は、評価されるステートメントによって異なります。 作業単位 は、以下のように定義されます。
上記の定義のうち、どれもブロック内のステートメントに適用されない場合は、そのステートメントが 1 つの 作業単位 になります。
規則
WORKSHARE 構文内のステートメントを確実に並行で実行するために、構文は、並列領域の 動的エクステント内に囲まなければなりません。 並列領域の動的エクステントの外側で WORKSHARE 構文を見つけたスレッドは、その構文内で ステートメントを逐次評価します。
WORKSHARE ディレクティブは、最も近いところにある動的に囲まれた PARALLEL ディレクティブが あれば、それをバインドします。
同じ PARALLEL ディレクティブとバインドする、 DO、SECTIONS、SINGLE および WORKSHARE ディレクティブをネストできません。
CRITICAL、MASTER、または ORDERED ディレクティブの動的エクステント内には、 WORKSHARE ディレクティブを指定できません。
WORKSHARE 構文の動的エクステント内には、 BARRIER、MASTER、または 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
関連情報