インテル® Fortran コンパイラー
OpenMP* 活用ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

このテキストは、Fortran プログラマー向けのマルチスレッド・プログラミングの入門として、OpenMP* について解説した資料です。OpenMP* を利用してのマルチスレッド・プログラミングについて、平易に説明しています。ここで紹介しているプログラムの実行例やコンパイルオプションの説明は、全てインテル® コンパイラー バー
ジョン 9.0 を用いています。より詳細な説明はコンパイラー・マニュアルなどをご参照ください。

1．
2．

はじめに . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

3．

OpenMP* マルチスレッド並列プログラミング . . . . . . . . . . . . . . . . . . . . 4

マルチスレッド・プログラミング . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

3.1

プログラミングの特徴 .... .......................................................................... 4

3.2

OpenMP* アーキテクチャー ..................................................................... 5

3.3

OpenMP* の適用の阻害要因とその対策 ................................................... 84．

OpenMP* によるマルチスレッド・プログラミング . . . . . . . . . . . . . . . . 9

4.1

宣言子の書式 ............... .......................................................................... 94.2

条件付きコンパイル ............................................................................... 10

4.3

OpenMP* ライブラリー .. ........................................................................ 10

4.4

OpenMP* 宣言子一覧 ........................................................................... 11

4.5

構造ブロック ................. ........................................................................ 125．

OpenMP* 指示構文の説明 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

5.1

PARALLEL 構文（並列実行領域の指定）................................................ 13

5.2

ワークシェアリング構文 ......................................................................... 16

5.3

データ環境 ........................................................................................... 21

5.4

同期構文 ...................... ........................................................................ 26

5.5

その他の宣言句 ............ ........................................................................ 30

5.6

ランタイム関数 / 環境変数 ..................................................................... 31

6．

OpenMP* の適用について . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32

7．

おわりに . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

付録 ̶ 自動並列処理と OpenMP* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
付録 ̶ OpenMP* サンプルプログラム. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

注記：『デュアルコア / マルチコア対応アプリケーション開発』は、次の 4 巻から構成されています。
1 インテル ® コンパイラー OpenMP* 入門
2 インテル ® C/C++ コンパイラー OpenMP* 活用ガイド
3 インテル ® Fortran コンパイラー OpenMP* 活用ガイド
4 インテル ® コンパイラー 自動並列化ガイド

本資料で言及されているインテル製品は、一般的な商業目的にのみ使用することを前提にしています。特定の目的に本製品を使用する場合、適合性の評価についてはお客様の責任になります。インテル製品は、医療、救命、延命措置、重要な制御または安全シ
ステム、核施設などの目的に使用することを前提としたものではありません。
本資料のすべての情報は、現状のまま提供され、インテルは、本資料に記載表現されている情報及びその中に非明示的に記載されていると解釈されうる情報に対して一切の保証をいたしません。また、本資料に含まれる情報の誤りや、それによって生じるいかな
るトラブル（P C パーツの破損などを含むがこれらに限られない）に対しても一切の責任と補償義務を負いません。また、本資料に掲載されている内容は、予告なく変更されることがあります。

1

インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

1 . はじめに
今後は、より多くのコアが一つのプロセッサー上に実装されるデュアルコアとマルチコアが一般的なプロセッサーとなることは間違いありません。デュアルコアとマルチコアの持つ大きな可能性とその能力を最大限に発揮するためのキーとなるのがマルチスレッドでのアプリケーション実行の高速化です。
このアプリケーションの高速化には、複数のスレッドが並列に処理を行うことが必要になります。ここで問題となるのは、アプリケーション・プログラムに対して並列処理を適用するための特別な作業やそのための開発工数が必要になるかということです。実際には、マルチスレッド化や並列化といった作業はそれほどの時間を必要とするものではありません。マルチスレッド対応の開発ツールがあれば、これらの並列化は容易に行うことが可能です。プログラムの開発者やプログラマーは、プログラムの本質的なロジックを記述することに専念し、並列化については、既に高度に最適化・並列化されたライブラリーを利用したり、並列化コンパイラーの支援をしたりすることによって、プログラムのマル
チスレッド化を図ることが現在では可能になっています。
インテル® コンパイラー バージョン 9.0 は、優れたマルチスレッド対応の開発ツールです。32bit と 64bit Linux*
及び 32bit と 64bit Windows* のオブジェクト・コードを作成し、それぞれのプラットフォームでのプログラムの性能を最大限に引き出すことを可能とします。バージョン 9.0 でサポートされているプログラムのマルチスレッド化は、
大きく 2 つに分けられます。一つは自動並列化、そしてもうひとつが OpenMP* のサポートです。自動並列化では、その名のとおりコンパイラーがソースコードを解析し、自動的にプログラムの構造に適したマルチスレッド実行が可能な実行モジュールを作成します。自動並列化のオプションによって、アプリケーション内で複数のスレッドや拡張機能の自動作成が可能になっています。OpenMP* はユーザーがプログラムの並列化を指示する構文をプログラム中に記述することで、マルチスレッド並列プログラムを開発する枠組みを提供します。バージョン 9.0 では、OpenMP* 2.5
仕様の実装がなされており、最新の OpenMP* の機能が利用可能となっています。ここでは、この OpenMP* によるマルチスレッド・プログラミングの基本を紹介します。

2

インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

2. マルチスレッド・プログラミング
OpenMP* の説明を始める前に、マルチスレッド・プログラミングについて少し説明します。スレッドとは OS による処理単位であり、OS は要求される処理タスクを分割しそれぞれをこのスレッドの単位で処理を行います。このスレッド
を複数の CPU に割り当てられ処理するのが、マルチスレッドによる並列処理となります。

Memory
CPU

CPU

CPU

逐次実行
プログラム
マルチスレッド・プログラミング

OpenMP* や自動並列コンパイル

並列実行
プログラム

図 .1 マルチスレッドによる並列実行

マルチスレッドは、プロセス内の仮想メモリー空間といったリソースやコンテキストを共有し、固有のスタックとプロ
グラムカウンター（PC）を個別に持つことになります。
個々のプロセスが固有の仮想空間上で動作するプロセスと異なり、このメモリー空間を共有することで、スレッドは並列処理を行う上で非常に効率的な実行を可能としています。メモリー空間の共有により、スレッド間でのデータのやり取りは直接アクセスが可能となり、O S を介した通信のようなオーバーヘッドの大きなオペレーションを必要としません。同時に、スレッドの生成や切り替えはプロセスの場合と比較して高速であり、システムのリソースへのインパクト
も非常に小さくなります。このようなスレッドの特性を最大限に活用することで、効率のよい並列処理を行うのが、マル
チスレッド・プログラミングです。

データ

スレッド

データ

スレッド

データ

スレッド

スレッドチーム

共有データ

スレッドチーム

データ

スレッド

データ

スレッド

データ

スレッド

図 .2 マルチスレッドによるリソースとコンテキストの共有

3

インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

3. OpenMP* マルチスレッド並列プログラミング
OpenMP* は、マルチスレッド並列プログラミングのための API（Application Programming Interface）です。
OpenMP* API は、1997 年に発表され、その後継続的にバージョンアップされている業界標準規格であり、多くのハードウェアおよびソフトウェア・ベンダーが参加する非営利団体（Open MP Architecture Review Board）によって管理されており、Linux*、UNIX* そして Windows* システムで利用可能です。OpenMP* は、C/C++ や Fortranと言ったコンパイラー言語ではありません。また、OpenMP* 自身はコンパイラーではなく、コンパイラーに対する並列処理の機能拡張を規定したものです。
したがって、OpenMP* を利用するには、
インテル® コンパイラー バージョン 9.0のような OpenMP* をサポートするコンパイラーが必要です。OpenMP* の詳細については、OpenMP* のホーム
ページ http://www.openmp.org/ に、その歴史も含めて詳細な情報があります。最新の OpenMP* のリリースは、

2005 年 5 月の OpenMP* 2.5 であり、この仕様では初めて、C/C++ と Fortran の双方の規格の統合がなされま
した。

1998

2002

2005

OpenMP*
C/C++ 1.0

OpenMP*
C/C++ 2.0

OpenMP*
Fortran
C/C++ 2.5

1997

1999

2000

OpenMP*
Fortran 1.0

OpenMP*
Fortran 1.1

OpenMP*
Fortran 2.0

図 .3 OpenMP* リリースの歴史

3.1 プログラミングの特長
C / C + + や F o r t r a n には、並列処理のための A P I が無かったために、それを補うものとして規定されたのがOpenMP* であるとも言えます。OpenMP* は、C/C++ や Fortran の言語規格に準拠しているため、OpenMP* を利用しても、プログラムの移植性や互換性を損なう事なく、並列処理を容易に適用することができます。
コンパイラーのサポート

OpenMP* を利用した並列プログラミングは、プログラムに対して OpenMP* で規定された宣言子を挿入し、コンパイル時にコンパイルオプションとして /Qopenmp スイッチ（Windows*）、-openmp スイッチ（Linux*）を指定することで可能となります。コンパイラーは、O p e n M P * 宣言子で指示された範囲を並列化したことをメッセージとして出力します。
明示的な並列化の指示

O p e n M P * 宣言子は、コンパイラーに対して並列化のためのヒントを与えるのでなく、明示的に並列化を指示するものです。したがって、間違った宣言子を指定しても、コンパイラーはその指示に従って並列化を行います。また、データの依存性などがあっても、コンパイラーは警告メッセージやエラーメッセージを出したり、その指示を無視したりすることなく忠実に並列化を行いますので、依存性があるループなどを O p e n M P * で並列化した場合には、計算結果が不正になります。一方、OpenMP* を使用した場合、スレッドの生成や各スレッドの同期コントロールといった制御をユーザーが気にする必要はありません。

4インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

プログラムの段階的な並列化が可能
プログラムの開発者やプログラマーは、コードの設計時から O p e n M P * を利用した並列処理を実装することも可能です。また、既に開発されたプログラムを、O p e n M P * を利用して段階的に並列化することも可能です。

OpenMP* での並列化を適用していて、計算などが不正になった場合、簡単にその部分だけを逐次実行に切り替えることができるので、プログラムのデバッグが非常に容易です。
自動並列化との併用
自動並列化と OpenMP* を併用することも可能であり、プログラムの一部だけを OpenMP* で並列化し、他の部分を自動並列化することも可能です。OpenMP* と自動並列化は、ハイレベルのマルチスレッド・ライブラリーを共有することで混在が可能となっています。また、オペレーティング・システム（32bit と 64bit Linux* 及び 32bitと 64bit Windows*）に関係なく並列処理の適用が可能となっています。
疎粒度での並列化の適用

OpenMP* での並列化では、自動並列化が難しい関数やサブルーチンの呼び出しを含むタスクでの並列化（疎粒度での並列化）も可能になります。コンパイラーの自動並列化では認識できないこのような粒度の大きな並列化では、よりオーバーヘッドの小さな並列化処理が可能となります。

3.2 OpenMP* アーキテクチャー
OpenMP* のアーキテクチャーは以下のようなものになります。

エンドユーザー

ユーザー層
プログラミング層（OpenMP* API）

アプリケーション
宣言子

システム層

OpenMP* ライブラリー

環境変数

実行時ライブラリー
スレッドライブラリー/オペレーティング・システム

図 .4 OpenMP* のアーキテクチャーO p e n M P * A P I は、プログラムの並列化領域やデータ属性などを指示する宣言子と並列処理を補助するためのOpenMP* ライブラリー、そして、並列処理を行う場合の実行環境を指定する環境変数から構成されます。これらは、デスクトップからスーパー・コンピューターまで、統一されたひとつの API となっています。従って、OpenMP* API
でプログラムの並列化を行うことで、システムのスケールアップに合わせてプログラムを書き直す必要はありません。
また、OpenMP* API をサポートしているプラットフォームであれば、現在及び将来のプラットフォーム間でのプログ
ラムの移行は非常に容易です。

5

インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

O p e n M P * のもっとも基本的な考え方は、プログラム中の計算負荷が大きなループに対して、その並列処理のための「指示」をコンパイラーに行うというものです。OpenMP* マルチスレッド・コンパイルをサポートするコンパイルシ
ステムは、この指示に従って並列処理の適用をコードに対して行います。実際には OpenMP* の適用はループについてだけ行うものではありませんが、以下の例では主に DO ループを並列化する事例を中心に説明を行います。

並列実行領域 （Parallel Region）!$OMP PARALLEL IF (N.GT.LIMIT) DEFAULT(NON)!$OMP& SHARED(n,a,b,c,x,y,z) PRIVATE(f,i,scale)f = 1.0
すべてのスレッドが実行!$OMP DO NOWAIT
do i = 1, n
並列ループ
z(i) = x(i) + y(i)（ワークシェアリング）
end do!$OMP END DO!$OMP DO NOWAIT
do i = 1, n
並列ループ
a(i) = b(i) + c(i)（ワークシェアリング）
end do!$OMP END DO
同期処理!$OMP BARRIER
scale = sum(a, 0, n) + sum(z, 0, n) + f……
すべてのスレッドが実行!$OMP END PARALLEL
図 .5 OpenMP* プログラミングの概要

6

インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

簡単なπの計算で OpenMP* プログラムを示します。このプログラムに OpenMP* 宣言子を挿入し、並列化した
例は次のようになります。
（Linux* でのコンパイル例と出力）$ cat -n pi.f90
1

program omp

2 !$use omp_lib

3

integer num_steps

4

real*8 step,x,pi,sum

56

num_steps = 100000000

7

step = 1.0D0 / dble(num_steps)8sum = 0.0D0

9 !$OMP PARALLEL PRIVATE(X)10nthread = OMP_GET_NUM_THREADS()

OpenMP* ランタイム関数

11 !$OMP DO REDUCTION(+:SUM)
12

do i = 1, num_steps

13

x = (dble(i)-0.5d0)*step

14

sum = sum + 4.0D0 / (1.0D0 + x * x)

15

OpenMP* 宣言子

end do16 !$OMP END DO
17 !$OMP END PARALLEL18

pi = step * sum

19

write (6,*) nthread,' Threads',' PI = ',pi

20

end program omp

21$ ifort -O3 -openmp _openmp-report2 pi.f90

コンパイルとメッセージ

ifort: Command line warning: openmp requires C style preprocessing; using fpp to preprocess
pi.f90(11) : (col. 6) remark: OpenMP DEFINED LOOP WAS PARALLELIZED.
pi.f90(9) : (col. 6) remark: OpenMP DEFINED REGION WAS PARALLELIZED.

環境変数の設定$ setenv OMP_NUM_THREADS 2$ time ./a.out
2 Threads PI =3.14159265358991

0.575u 0.003s 0:00.31 183.8%

0+0k 0+0io 153pf+0w

図 .6 OpenMP* プログラムのコンパイルと実行例

OpenMP* を利用した並列プログラミングは、プログラムに対して OpenMP* で規定された宣言子を挿入し、コンパイル時にコンパイル・オプションとして /Qopenmp スイッチ（Windows *）、-openmp スイッチ（Linux *）を指定することで可能となります。O p e n M P * 宣言子は、コンパイラーに対して並列化のためのヒントを与えるのでなく、明示的に並列化を指示するものです。したがって、間違った宣言子を指定してもコンパイラーはその指示に従って並列化を行います。また、データの依存性などがあっても、コンパイラーは警告メッセージやエラーメッセージを出し、その指示を無視することなく忠実に並列化を行いますので、依存性があるループなどを OpenMP* で並列化した場
合には計算結果が不正になります。一方、OpenMP* を使用した場合、スレッドの生成や各スレッドの同期コントロー
ルといった制御をユーザーが気にする必要はありません。コンパイラーは OpenMP* の指示によって並列化を行ったことをメッセージとして出力します。

7インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

3.3 OpenMP* の適用の阻害要因とその対策
OpenMP* によるマルチスレッド化の適用に際しては、いくつかの条件を満たしている必要があります。逆に、このような条件に適応できないケースでは OpenMP* による並列化はできません。
ここでは、OpenMP* によるマルチスレッドの適用の対象となるのは、C/C++ と Fortran などでの「ループ」による反復計算部分として説明します。
● ループの反復回数がループの実行を開始される時に明らかになっている必要があります。従って、while ループなどの並列化は通常はできません。
● ループの並列化に際して、十分な計算負荷がそのループにあることが必要となります。
● ループ内の演算は、相互に独立である必要があります。言い換えれば、各反復計算の実行順序が計算の整合性に影響を与えないことが必須です（この場合、計算の丸め誤差などでの計算順序の差異については、自動並列化
では考慮はなされません）。ループの各反復が他の反復計算の結果を参照したりする場合には並列化はできません（依存関係）。

DO I=1, N
A[ インデックス計算式 1] = ・・・・・・・・・・ = A[ インデックス計算式 2]・・・・・・
END DO
ここでは、インデックス計算式 1 の値は、各反復時に異なった値となることが必要です。また、インデックス計算式

1 とインデックス計算式 2 の値が異なる場合には、参照関係に依存性が生じます。
● 配列の総和を計算するような場合には、実際には各反復計算の結果は相互依存します。しかし、ループ構造が明確な場合などは、コンパイラーがソースコードを変換し、この見かけの依存性を排除することも可能となります。
● ループ内に外部関数の呼び出しがあるような場合には、外部関数の呼び出しによる依存関係を明確にして、関数のデータのスコーピングを行う必要があります。

8インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

4. OpenMP* によるマルチスレッド・プログラミング
4.1 宣言子の書式
OpenMP* の宣言子の書式には、Fortran プログラムの形式に合わせて固定形式と自由形式があります。固定形
式は、一般には Fortran 77 プログラムの標準ソース形式と呼ばれおり、
プログラムは決まったフィールドにそれぞれ、プログラムを記述する必要があります。自由形式では、これらの制限がありません。
一般にコンパイラーは、名前が拡張子 f90 で終わるソースファイルは自由形式と見なされ、名前が拡張子 f または F で終わるソースファイルは固定形式と見なされます。また、コンパイルオプションでも指定することができます。固定形式でのプログラムの記述方法については、各処理系のマニュアルなどをご参照ください。このドキュメントでは、例として示したプログラムは固定形式で記述してあります。

OpenMP* 宣言子は、Fortran のコメント行の書式に従っています。これは、OpenMP* コンパイルを無効とする
場合や OpenMP* をサポートしていない処理系の場合は、コメント行とみなされます。宣言子は、次のように行の先頭に !$OMP と書き、次に宣言名、宣言句 1 などの指定を行います。

!$OMP directive [clause[[,] clause] … ]自由形式では、任意のカラムから宣言子を記述できます。宣言子を継続する場合には、行の最後にアンパサンド（&）を記述します。

!$OMP directive [clause[[,] clause] … ] &!$OMP& [clause[[,] clause] … ]Fortran77 のコメント行の形式である次のような形式でも、OpenMP* 宣言子の指定は可能です。
c$OMP directive [clause[[,] clause] … ]*$OMP directive [clause[[,] clause] … ]c$OMP directive [clause[[,] clause] … ]c$OMP+[clause[[,] clause] … ]1. データ属性の指定などを行うもので、英文で clause と記述された部分です。日本語マニュアルでは、句や節などと訳されます。このテキストでは、宣言句という名称でこの属性指定の部分を記述しました。

9インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

4.2 条件付きコンパイル
OpenMP* では、プログラムの互換性と管理のために条件付きコンパイルのために次のような機能があります。
C23456789
C$
IAM = OMP_GET_THREAD_NUM()
この場合、OpenMP* のコンパイルが有効な場合には、C$ は 2 つの空白に置き換えられます。先頭に !$ を指定しても同じです。

!$!$

IAM = OMP_GET_THREAD_NUM() + &index

また、#ifdef での条件付きコンパイルも可能です。

#indef _OPENMP
IAM = OMP_GET_THREAD_NUM()#endif

4.3 OpenMP* ライブラリー
OpenMP* API では、並列処理の補助を行う関数として以下のような OpenMP* ライブラリーが用意されています。
環境変数

説 明

逐次実行領域での呼び出し並列実行領域での呼び出しcall omp_set_num_threads(integer)

並列実行領域で使用するスレッド数を設定する

スレッド数の設定

呼び出し不可integer omp_get_num_threads()

並列実行領域のスレッド数を返す

1

スレッド数

integer omp_get_max_threads()

最大のスレッド数を返す

OMP_NUM_THREADS の設定値

integer omp_get_thread_num()

並列スレッドの番号を 0 から返します0

integer omp_get_num_procs()

プログラムで使用可能なプロセッサー
数を返すシステムの物理 CPU 数

logical omp_in_parallel()

並列実行中であれば真を返す.FALSE.

call omp_set_dynamics (logical)

スレッド数の動的制御有効、無効の設定

logocal omp_get_dynamic()

スレッド数の動的制御の判定

call omp_set_nested(logical)

ネストされた並列実行領域の有効、無効の設定

logical omp_get_nested()

ネストされた並列実行領域の判定

各スレッド番号.TRUE.
呼び出し不可有効な場合には真を返す
呼び出し不可有効な場合には真を返す

表 .1 OpenMP* 補助関数（一部のみ掲載）

10インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

これらの OpenMP* 関数は先頭が OMP で始まっているので、型宣言を忘れた場合には関数の値が実数として返されるため、正しく返されません。OpenMP* の API では、この問題に対応するために omp_lib というモジュールが提供されます。次のような形式で利用することができます。

program omp!$ use omp_lib.
!$omp parallel
Iam = omp_get_thread_num()!$omp end parallel.
end program omp
表 .1 に記述したように、これらの関数は呼び出し可能な場所が決まっています。また、呼び出された場所によって、返す値などが変わりますので注意が必要です。

4.4 OpenMP* 宣言子一覧
OpenMP* 構文構成は、以下の５つのカテゴリに分類可能です。

● 並列実行領域（Parallel Regions）構文● ワークシェアリング（Worksharing）構文● データ環境（Data Environment）構文● 同期（Synchronization）構文● ランタイム関数 / 環境変数（Runtime functions/environment variables）

これらの構文での代表的な宣言子を以下に示します。
● 並列実行領域（Parallel Regions）構文!$OMP PARALLEL● ワークシェアリング（Worksharing）構文!$OMP DO!$OMP SECTIONS!$OMP SINGLE!$OMP WORKSHARE● データ環境（Data Environment）構文
宣言子 : THREADPRIVATE
宣言句 : SHARED、PRIVATE、LASTPRIVATE、REDUCTION、COPYIN、COPYPRIVATE● 同期（Synchronization）構文
宣言句 : CRITICAL、BARRIER、ATOMIC、FLUSH、ORDERED、MASTER● ランタイム関数 / 環境変数（Runtime functions/environment variables）

11インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

4.5 構造ブロック
O p e n M P * 宣言子の構文は、構造ブロックと呼ばれる単位に対して適用されます。F o r t r a n の場合には、OpenMP* 宣言子の構文の開始と終了をそれぞれ指定する指示文に囲まれた範囲が、この構造ブロックになります。
構造ブロックについては、この部分からの飛び出しや飛び込みは禁止されます。ただし、stop 文の実行のための飛び出しは可能となります。
この構造ブロックは、Fortran の一つのステートメントでも複数のステートメントからも構成可能です。

!$OMP PARALLEL!$OMP PARALLEL10wrk(id) = garbage(id)10wrk(id) = garbage(id)res(id) = wrk(id)**230

res(id)=wrk(id)**2

if(conv(res(id)) goto 10

if(conv(res(id))goto 20!$OMP END PARALLEL
print *,idgo to 10!$OMP END PARALLEL
if(not_DONE) goto 30
20

構造ブロック

print *, id

非構造ブロック

図 .7 構造ブロックの定義

12インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

5. OpenMP* 宣言子の構文説明
5.1 PARALLEL 構文（並列実行領域の指定）
OpenMP* による並列処理モデルの柱となるコンセプトは 並列実行領域（Parallel Region）です。並列実行領域
は、
DO ループに限らずプログラムの並列化を行うべきコードセグメントを指定することができます。並列実行領域では、
ワークシェアリング構造が設定され、この部分は全てのスレッドによって分割処理されます。また、クリティカル・セク
ション構造が指定された場合には、その部分は同時にただ一つのプロセスだけが処理を行います。PARALLEL 構造を構築できるのは、一つにプログラム単位（メインやサブルーチンなど）内で、G O T O 文などでの飛び出しや飛び込みの無い、一つ以上の Fortran 文から構成されるプログラム領域です。並列実行領域は、プログラム実行時には指定されてスレッド数のスレッドによって並列に実行されます。

PARALLEL 構造の指定は、以下のようになります。!$OMP PARALLEL / $OMP END PARALLEL で並列実行
するプログラムブロックを囲みます。

!$OMP PARALLEL [clause [[,] clause]
並列実行するプログラムブロック!$OMP END PARALLEL
コンパイラーは宣言句（clause）に記述してある付加情報に基づき、並列化処理のためのコードを生成します。

OpenMP* の実行モデル
OpenMP* のプログラミングモデルでは、Fork-Join モデルと呼ばれるもので逐次実行部分（シングルスレッドの実行）と並列実行（マルチスレッドのマルチプロセッサー、マルチコアプロセッサー上での実行）が交互に切り替わって実行されます。

【 Fork 】複数のスレーブスレッドを生成し、並列実行を開始します。

マスタースレッド

逐次実行するプログラムブロック

スレーブスレッド!$OMP PARALLEL DO [clause[[,]clause]…]DO I = 1, N
DO ループの繰り返しを各スレッドに分割し、並列に実行します。

END DO!$OMP END PARALLEL DO
逐次実行するプログラムブロック!$OMP PARALLEL DO [clause[[,]clause]…]DO I = 1, N
DO ループの繰り返しを各スレッドに分割し、並列に実行します。

END DO!$OMP END PARALLEL DO
逐次実行するプログラムブロック【 Join 】他のスレッドの処理の完了を待つための同期処理を行います。全てのスレッドの動作が完了す

この Fork と Join 操作により、逐次実行と並列実行を繰り返します。

るとスレーブスレッドは終了し、マスタースレッドのみが実行を継続します。

図 .8 Fork-Join モデルでの並列処理

13インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 31）OpenMP* の処理では、最初にマスタースレッドが起動されてプログラムの実行を開始します。このマスタースレッ
ドは、逐次的にプログラムの処理を行います。

2）マスタースレッドの実行が OpenMP* 宣言子 !$OMP PARALLEL の部分に到達すると、スレーブスレッドと呼ばれるスレッドを生成（スレッドを Fork する）
し、分割されたプログラムのタスクを並列に処理します。

3）このマスタースレッドとスレーブスレッドの処理は、プログラム中での並列実行領域の終了指示文、! $ o m p e n dparallel の部分に到達すると終了します。この終了時には、全スレッドが各自の処理を終了するまで、先に終了したスレッドも待つことになり同期処理を必要とします。

4）全スレッドが完了した時点（スレッドを Join する）で、プログラムの実行処理は再びマスタースレッドだけが行うことになります。
このような処理を繰り返して、プログラムの実行を行うので、 Fork-Join モデルと呼ばれています。

PROGRAM OMP!$

USE OMP_LIB

配列 A は各スレッドで共有されます。DO
ループの繰り返しを各スレッドに分割して、並列実行します。

REAL*8 A(4,1000)
CALL OMP_SET_NUM_THREADS(4)N=1000REAL*8 A(4,1000)!$OMP PARALLELOMP_SET_NUM_THREADS(4)ID = OMP_GET_THREAD_NUM()+1
CALL POOH(ID, A,N)!$OMP END PARALLELWRITE (*,*) 'all done'

POOH(0,A,N)

POOH(1,A,N)

POOH(2,A,N)

POOH(3,A,N)

END
SUBROUTINE POOH(ID,A,N)
REAL*8 A(4,*)
DO I= 1, N
A(ID,J) = 1.0
END DOWRITE (*,*) 'all done'
この時点で全スレッドの完
各スレッドは、了を待ちます。
（同期処理）

RETURN
END
図 .9 並列実行領域の設定と並列処理

また、OpenMP* プログラムでは、サブルーチンなどの手続きに、PARALLEL 構造の設定なしで OpenMP* 宣言子の指定が可能です。
このような宣言子を親無し宣言子と呼んでいます。
このような親無し宣言子を含むサブルーチン
は、逐次実行領域からも並列実行領域からも呼び出すことが可能であり、並列実行領域から呼び出された場合だけ並列処理を行います。このようなプログラムの並列実行領域からのサブルーチン呼び出しを含む場合を並列実行領
域の動的範囲と呼んでいます。

14インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

ソースファイル main.f
PROGRAM OMPINTEGER OMP_GET_THREAD_NUM!$OMP PARALLELCALL WHOAMI
構文的範囲!$OMP END PARALLELWRITE (6,*) 'All Done'
CALL WHOAMI!$OMP PARALLEL
IF (OMP_GET_THREAD_NUM().EQ.1)&CALL WHOAMI!$OMP END PARALLELSTOP
END PROGRAM OMP
ソースファイル whoami.f
SUBROUTINE WHOAMI
EXTERNAL OMP_GET_THREAD_NUM
INTEGER IAM, OMP_GET_THREAD_NUM
IAM = OMP_GET_THREAD_NUM()!$OMP CRITICALWRITE (6,*) 'Hello from',IAM!$OMP END CRITICAL
親無し宣言子RETURN
END

並列実行領域の動的範囲
並列実行領域内での宣言子の指定は、プログラムユニット間でも可能です。
この 例では 、m a i n . f 内で の 2 番 目のWHOAMI の呼び出しは、逐次実行領域からになりますので、whoami.f 内の並列化宣言子は無視され、通常の逐次処理プログラムとして、処理されます。

図 .10 並列実行領域の動的範囲

ここでは並列実行領域から関数を呼び出し、呼び出された関数内で OpenMP* の構文指定が行われる例を示しています。このように並列実行内での宣言子の指定はプログラムユニット間でも可能です。ここでは、m a i n . f 内での 2
番目の WHOAMI の呼び出しは、逐次実行領域からの呼び出しになりますので、whoami.f 内での並列化宣言子は無視され、通常の逐次処理プログラムとして処理されます。

15

インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

5.2 ワークシェアリング構文
並 列 実 行 領 域内の F o r t r a n プログラムは、全スレッドで実 行されます。従って、並 列 処 理 可 能な領 域を

P A R A L L E L 構造で指定しても並列処理による計算時間の短縮はできません。並列実行領域での「ワークロード」を
各スレッドに分担させることが必要になります。このような「ワークロード」の分散はプログラム内で明示的に行なうことも可能です。OpenMP* API では、各スレッドにつけられた番号などを取得する関数が用意されています。これらの関数を使えば、例えば、次のような形でプログラムの処理の分散も可能です。
（1）逐次実行コード

do i = 1, n ; a(i) = a(i) + b(i) ; end do!$OMP PARALLEL PRIVATE (id,i,istart,iend)
id = omp_get_thread_num();
Nthrds = omp_get_num_threads();（ 2 ）OpenMP* での並列実行領域の指定

istart = id * n / Nthrds;
iend = (id+1) * n / Nthrds;
do i=istart,iend ; a(i)=a(i)+b(i) ; end do!$OMP END PARALLEL!$OMP PARALLEL（ 3 ）OpenMP* での並列実行領域の指定とワーク
シェアリング構文!$OMP DO SCHEDULE(STATIC)
do i = 1, n ; a(i) = a(i) + b(i) ; end do!$OMP PARALLEL DO SCHEDULE(static)
do i = 1, n ; a(i) = a(i) + b(i) ; end do

図 .11 OpenMP* によるワークシェアリングの実装（1）のような D O ループの逐次処理は、並列実行領域内でのスレッド数でループを分割することで、個々のスレッドが分担するループの範囲（ループ長）を決定し、それに基づいて個々のスレッドで（2）に示すような形で並列処理することが可能となります。しかし、実際には、このような明示的なプログラムは煩雑ですし、また、実装も容易ではありません。OpenMP* のワークシェアリング構文では、このようなワークロードのスレッドへの分担を指示する宣言子が用意されています。この例を（3）に示してあります。

DO 構文
DO 構文は直後の DO ループの処理を各スレッドに分割して、並列実行します。形式は、次のようになっています。
!$OMP DO [clause [[,] clause]..]DO ループ[!$OMP END DO [NOWAIT]]

16

インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3【 Fork 】複数のスレーブスレッドを生成し、並列実行を開始します。

マスタースレッド

逐次実行するプログラムブロック

スレーブスレッド!$OMP PARALLEL DO [clause[[,]clause]…]DO I = 1, N
DO ループの繰り返しを各スレッドに分割し、並列に実行します。

END DO!$OMP END PARALLEL DO
逐次実行するプログラムブロック!$OMP PARALLEL DO [clause[[,]clause]…]DO I = 1, N
DO ループの繰り返しを各スレッドに分割し、並列に実行します。

END DO!$OMP END PARALLEL DO
逐次実行するプログラムブロック【 Join 】他のスレッドの処理の完了を待つための同期処理を行います。全てのスレッドの動作が完了す

この Fork と Join 操作により、逐次実行と並列実行を繰り返します。

るとスレーブスレッドは終了し、マスタースレッドのみが実行を継続します。

図 .12 DO ループに対する OpenMP* での並列処理の適用

PROGRAM OMP!$ USE OMP_LIB
REAL*8 A(100)
CALL OMP_SET_NUM_THREADS(4)!$OMP PARALLEL DO
DO I = 1, 100

REAL*8 A(100)

配列 A は各スレッドで共有されます。DO
ループの繰り返しを各スレッドに分割して、並列実行します。

OMP_SET_NUM_THREADS(4)CALL POOH(I,A)
END DOPOOH(I,A)!$OMP END PARALLEL
DO/

I=1,2,3..

WRITE (*,*) 'all done'

POOH(I,A)
I=26,27,..

POOH(I,A)

POOH(I,A)

I=51,52..

i=76,77..

END
SUBROUTINE POOH(I,A)
REAL*8 A(*)

WRITE (*,*) 'all done'

A(I) = 1.0
RETURN

この時点で全スレッドの完
各スレッドは、（同期処理）
了を待ちます。

END
図 .13 DO ループに対するワークロードとデータの分散並列処理

ループの分割については、オプションで分割方法を指定することもできます。DO 構文に SCHEDULE 句を指定してこの分割方法を指示します。

!$OMP DO SCHEDULE(type[,chunk]) [clause [[,] clause]..]DO ループ[!$OMP END DO [NOWAIT]]

17

インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

TYPE

説 明

STATIC

繰り返し数は、chunkで指定したサイズに分割されます。分割された部分は、スレッドの番号順でラウンドロビン形式（全てのスレッドに対して、平等に巡回的に割り当てる）で各スレッドに静的に割り当てられます。chunkの指定が無い場合には、均等に分割されます。

DYNAMIC

オプションで指定可能なchunkで指定したサイズに分割され、各スレッドは割
繰り返し数は、り当てられた繰り返し部分を終了すると繰り返し数の次のセットが動的に割り当てられます。
オプションのchunkの指定が無い場合には、1が設定されます。

GUIDED

guidedを指定した場合、chunkのサイズは繰り返し数を各スレッドに割り当てた毎に指数関数的に減少します。
オプションのchunkの指定には、割り当てごとの最小繰り返しの設定が可能です。
オプションのchunkの指定が無い場合には、1が設定されます。

RUNTIME

スケジュールの指定を実行時に指定します。オプションの type 及び chunk は環境変数
OMP_SCHEDULEの設定によって実行時に決定されます。環境変数OMP_SCHEDULEがない場合には、SCHEDULE（STATIC）が設定されます。

表 .2 ループ分割のスケジューリング・オプション

各パラメーターの指定時のループの分割を模式的に記述すると次のようになります。ここでは、4 プロセッサーでの並列処理における各スケジューリングの各プロセッサーへの処理の分配を示しています。

SCHEDULE（STATIC,6）
4 プロセッサー
SCHEDULE（STATIC,6）
4 プロセッサー
SCHEDULE（STATIC,6）
4 プロセッサー
図 .14 DO ループの並列処理におけるスケジューリング例

DO WHILE ループなど繰り返し数を持たないループは、指定できません。NOWAIT パラメーターを記述した場合、個々のプロセスは DO 構文の実行後、ただちに後に続く処理を行います。NOWAIT を指定しない場合は、プロセスは他の全てのプロセスが DO 構文を終了するまで待ち状態になります。

18

インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

SECTIONS 構文
S E C T I O N S 構 文は、F o r t r a n 90 の S E L E C T ステートメントと同 様の構 造です。S E C T I O N S 構 文では、
SECTION 宣言子で囲まれた個々のコードブロックがひとつのスレッドに割り当てられて処理を行います。

!$OMP SECTIONS [clause [[,] clause]..][!$OMP SECTION]
並列実行するコードブロック[!$OMP SECTION

並列実行するコードブロック!$OMP END SECTIONS [NOWAIT]
宣言句 NOWAIT を記述した場合、個々のプロセスは SECTIONS 構文の実行後、ただちに後に続く処理を行います。NOWAIT を指定しない場合は、プロセスは他の全てのプロセスが SECTIONS 構文を終了するまで待ち状態になります。SECTION 宣言子は SECTIONS/END SECTIONS 宣言子の外に記述することはできません。SECTION から、他の SECTION へ分岐、移動することはできません。
マスタースレッド
逐次実行するプログラムブロック

スレーブスレッド!$OMP PARALLEL [clause[[,]clause]…]!$OMP SECTIONS
並列実行するプログラムブロック!$OMP SECTION

並列実行するプログラムブロック

idle idle

並列実行するプログラムブロック!$OMP SECTION

逐次実行するプログラムブロック

図 .15 SECTIONS 構文の実行!$OMP SECTION

実行を指定したスレッド数に対して、SECTION 宣言子で囲まれるブロックが少ない場合には、仕事が割り当てられないスレッドができます。逆に、S E C T I O N 宣言子で囲まれるブロックが多い場合には、先の仕事を終えたスレッドが残りのブロックを分担して実行します。
!$OMP SECTIONSINGLE
構文!$OMP END SECTIONSSINGLE 構文は並列実行領域の中でのみ記述できます。SINGLE 構文で指定されたコードブロックは、ただ一つの!$OMP END PARALLEL
プロセスでのみ実行されます。
NOWAIT が指定されていない場合は、END SINGLE のところで同期します。シンタック

スは以下の通りです。
!$OMP SINGLE [clause [[,] clause]..]
実行するコードブロック!$OMP END SINGLE [NOWAIT]

19

インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

マスタースレッド
逐次実行するプログラムブロック

スレーブスレッド!$OMP PARALLEL
並列実行するプログラムブロック!$OMP SINGLE
一つのスレッドだけで処理するブロック

idle idle

idle idle!$OMP END SINGLE
並列実行するプログラムブロック!$OMP END PARALLEL
逐次実行するプログラムブロック

図 .16 SINGLE 構文の実行

この SINGLE 構文は、SECTIONS 構文で SECTION 宣言子の指定がひとつしかない場合と同等です。

WORKSHARE 構文
WORKSHARE 構文は、Fortran の配列演算式、FORALL、WHERE 及び MATMUL などの要素、変形関数を処理するために導入されました。WORKSHARE 構文で囲まれたコードは複数の作業単位に分割され、各単位は一回だけ実行されるようにスレッド間で分割されます。

!$OMP WORKSHARE

実行するコードブロック!$OMP END WORKSHARE [NOWAIT]
プログラム例としては、以下のようなものになります。WORKSHARE 構文でのワークロードの分散はコンパイラーの制御に委ねられます。SCHEDULE 宣言句などの指定はできません。

REAL A(100,200), B(100,200), C(100,200)...
!$OMP PARALLEL!$OMP WORKSHARE
A=B+C!$OMP END WORKSHARE!$OMP END PARALLEL
結合構文

OpenMP* では PARALLEL 構文とワークシェアリング構文を結合した次のようなショートカット構文が定義されています。

PARALLEL DO 構文
PARALLEL SECTIONS 構文
PARALLEL WORKSHARE 構文
これらは PARALLEL 宣言子の直後にそれぞれのワークシェアリング宣言子を指定した場合と同じ意味を持ちます。

20

インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

5.3 データ環境
いままで紹介した OpenMP* 宣言子には、宣言句（clause）という表示がありました。この宣言句は、OpenMP *構文機能に対する付加情報を与えるものです。この与えられた付加情報によって、コンパイラーは並列実行のための並列化を行ないます。OpenMP* 宣言子と指定可能な宣言句の関係は、以下のようになります。

PARALLELIFDOSECTIONSWORKSHARESINGLE●●SCHEDULEPARALLELSECTIONS

PARALLEL
WORKSHAPE

●

●

●

●

●

●

●

PRIVATE

●

SHARE

●

●

●

●

DEFAULT

●

●

●

●

FIRSTPRIVATE

●

●

●

●

●

●

●

●

●

●

●

●

●

●

LASTPRIVATECOPYIN●PARALLEL
DO

●

●

●

●

●

●

●

●
●

●

ORDERED●NOWAIT●

NUM_THREADS●●

COPYPRIVATE
REDUCTION

●

●

●
●

●

●

●

表 .3 OpenMP* 宣言子と宣言句の指定

ここで、データスコープ属性を指定する宣言句は、並列実行領域での変数の取り扱いについての記述を行なうものです。データスコープとは、並列プログラム内での変数が、スレッド毎に独立の記憶域を持ち、それぞれ異なった値を持つものとなるか、プログラム内で一つの記憶域で管理されるかを決定するものです。

SHAREDPRIVATE

全スレッドがアクセス可能

スレッド毎に独立にデータを割り当て• COMMON ブロック• OpenMP* 宣言子でのグローバル

全てのプログラムユニット内でア• MODULE 変数

THREADPRIVATE 指定（大域）変数

クセスが可能な変数• SAVE 属性の変数（COMMON ブロック及び• 初期化データ

MODULE 変数）

プログラムユニット内だけでアク• OpenMP* でのデフォルト• OpenMP* 宣言子での PRIVATE 指定

セスが可能な変数• OpenMP*宣言子での SHARED 指定• ループの反復変数

ローカル（局所）変数

表 .4 データスコープ：並列実行領域内での変数の取り扱い

21

インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

ソースファイル main.f
PROGRAM OMP
COMMON /WORK/ A(10)REAL*8 A
INTEGER INDEX(10)!$OMP PARALLELCALL SORT(INDEX)!$OMP END PARALLELWRITE (6,*) INDEX(1)STOP
END PROGRAM OMP

ソースファイル sort.f
SUBROUTINE SORT(INDEX)COMMON /WORK/ A(10)REAL*8 A
INTEGER INDEX(*)
REAL*8 TEMP(10)INTEGER COUNTSAVE COUNT…….
…….
RETURNEND

配列 A 、INDEX 、変数 COUNT は各スレッド間で共有されます。配列 TEMP は、各スレッドが個々に持つデータとなります。

A, INDEX, COUNT

TEMP

TEMP

TEMP

A, INDEX, COUNT

図 .17 並列実行領域での変数の取り扱い

ここでは、並列領域を実行する際のデータ環境の制御について説明します。

THREADPRIVATE 宣言子
この宣言子はスレッド間でのデータ環境を定義するための宣言文であり、COMMON ブロック及びグローバル変数をスレッド間では独立とし、同じスレッド間では共有する枠組みを提供します。
この宣言子はプログラムユニットの宣言部分のセクションに記述しなければなりません。個々のスレッドは指定された COMMON ブロック及びグローバル変数のコピーを保持します。したがって、それぞれの COMMON ブロック及びグローバル変数に行われたデータの更新は他のスレッドのデータには反映されません。プログラムの逐次実行領域、および MASTER 宣言子指定の領域では THREADPRIVATE で指定された COMMON ブロックへのアクセスはマス
タースレッドの COMMON ブロック及びグローバル変数が使用されます。
最初の並列実行領域を実行する際には、THREADPRIVATE のデータの内容は宣言句 COPYIN が PARALLEL
宣言子に指定されていない場合未定となります。C O M M O N ブロックの変数が D A T A 文で初期化されている場合、それぞれのスレッドのコピーは最初の 1 回だけ初期化されます。
後に続く並列実行領域では、スレッドの数がプログラムの全ての並列実行領域にわたって同じであることを条件として THREADPRIVATE のコモンブロックのデータは保存されます。シンタックスは以下の通りです。

!$OMP THREADPRIVATE （list）
ここで、list に COMMON ブロック名を指定する場合は、スラッシュ（/）で囲みます。

22

インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

COMMON /JUNK/ NX
COMMON /STUFF/ A,B,C!$OMP THREADPRIVATE (/JUNK/,/STUFF/)
NX = 32
C = 17.9. . .
!$OMP PARALLEL PRIVATE(NX2,CSQ) COPYIN(/JUNK/,C)
NX2 = NX * 2
CSQ = C*C
. . .
次の例では、マスタースレッドの THREADPRIVATE で宣言されたデータが、並列実行領域での各スレッドでの

THREADPRIVATE で宣言されたデータにコピーされます。
データスコープ宣言句

PRIVATE（list）
マルチスレッド・プログラミングでは、DO ループの制御変数のように、スレッド毎に異なる値をもつ変数が必要になります。PRIVATE 宣言句の list に指定された変数は、スレッド毎に独立に領域が確保されます。これらの変数は、スレッド内だけでアクセスされる変数となります。PRIVATE 宣言句に指定された変数は、並列実行領域でスレッドがFork される毎に作成されます。従って、これらの変数の値は、並列実行領域の開始時点では全て値が未定義になっています。DO ループ及び FORALL ループの制御変数は、OpenMP* では全て PRIVATE 属性の変数と定義されます。

SHARED（list）

OpenMP* でのデータスコープは、指定が無い場合にはプログラム内で一つの記憶域として管理される SHARED
属性となります。

DEFAULT（SHARED｜PRIVATE｜NONE）

DEFAULT 宣言句は、並列領域内にある全ての変数のデータ属性に対して省略時（変数の定義がない場合）の取り扱いを PRIVATE 属性とするか、SHARED 属性とするかを指定します。

DEFAULT（PRIVATE）の指定を行った場合、THREADPRIVATE で指定された変数と COMMON ブロックを除き、並列領域にある全ての COMMON ブロック、変数をスレッドにプライベートなコピーを作成します。これは一つ一つの変数を PRIVATE（）に記述した場合と同様となります。

D E F A U L T（S H A R E D）の指定を行った場合、並列実効領域にある全ての変数は全てのスレッドによって共有されます。明示的に default の指定を記述していない場合は、DEFAULT（SHARED）となります。

D E F A U L T（N O N E）を指定した場合、P R I V A T E と S H A R E D のスコーピングに関しては何ら規定値を持たないことを指示します。この場合、並列領域にある全ての変数について、PRIVATE、SHARED、FIRSTPRIVATE、LASTPRIVATE、あるいは REDUCTION のスコーピング属性を与える必要があります。
変数は PRIVATE、SHARED、FIRSTPRIVATE、LASTPRIVATE、REDUCTION 指定によって、デフォルトの指定から除外することも可能です。したがって、次のような指定方法も問題ありません。

23インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3!$OMP PARALLEL DO DEFAULT(PRIVATE),!$OMP& FIRSTPRIVATE(I), SHARED(X),!$OMP& SHARED(R), LASTPRIVATE(I)FIRSTPRIVATE（list）

FIRSTPRIVATE は PRIVATE の機能のスーパーセットです。list に記述された変数は PRIVATE と同様な取り扱いとなりますが、その値は並列実行領域の開始時に逐次実行部分の変数の持つ値を各スレッドの PRIVATE 変数に値がコピーされます。

LASTPRIVATE（list）
並列実行領域が終了した時点では、並列実行領域での PRIVATE 変数の値は不定になります。LASTPRIVATE
は PRIVATE の機能のスーパーセットです。list に記述された変数は PRIVATE と同様な取り扱いとなりますが、その値は並列実行の際の最後のイタレーションで保持された値を持ちます。SECTION 構文の場合も、同様に逐次実行の際の最後の SECTION における値がコピーされます。

PROGRAM TEST
IS = 0C$OMP PARALLEL DO FIRSTPRIVATE(IS)C$OMP+ LASTPRIVATE(IS)DO J=1,1000
IS = IS + J
1000 CONTINUE
print *, IS
この例では、各スレッドは is=0 で計算を開始します。並列実行領域の終了後の print 文では、最後の反復計算時の値が保持されるため、is の値は j=1000 の計算時の数値となります。

COPYIN（list）

COPYIN は、THREADPRIVATE 宣言子で宣言されたグローバル変数に対して、FIRSTPRIVATE 宣言句に指定された変数と同様にマスタースレッド（逐次実行部分）の値をコピーします。list には必ずしもコモンブロック名を記述する必要はありません。THREADPRIVATE で指定したコモンブロックのメンバーである変数名でも構いません。

24インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

COPYPRIVATE（list）

COPYPRIVATE は、指定された PRIVATE 属性をもつ変数を他のスレッドにブロードキャストします。
この宣言句は、次のようにデータの読み込み時などにそのデータの各スレッドにブロードキャストするのに便利な機能を提供します。

!$OMP PARALLEL PRIVATE(A,B)...
!$OMP SINGLE
READ(24) A!$OMP END SINGLE COPYPRIVATE(A)B = A*A...
!$OMP END PARALLEL

25

インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

5.4 同期構文
同期構文には、MASTER、CRITICAL、BARRIER、ATOMIC、FLUSH、ORDERED の 6 つの宣言子があります。

MASTER 宣言子
MASTER / END MASTER 宣言子で囲まれたコードブロックはマスタースレッドのみで実行されます。
!$OMP MASTER

実行するコードブロック!$OMP END MASTER
マスター以外のスレッドはこのコードブロックをスキップし、次の実行に移ります。M A S T E R 宣言子のエントリー、または出口には同期ポイントは設けられません。

CRITICAL 宣言子
クリティカル・セクションは、指定したコードブロックを同時に 1 つのプロセスだけが実行することを指示するものです。同コードブロックを実行する他のプロセスは、クリティカル・セクションを実行しているプロセスが終了するのを待たなければなりません。

CRITICAL 宣言子のシンタックスは以下の通りです。
!$OMP CRITICAL [(name)]
実行するコードブロック!$OMP END CRITICAL
クリティカル・セクションに名前を付けることができます。同じ名前を持つクリティカル・セクションは、同一のものとして、クリティカル・セクションにまたがっての排他制御が可能となります。省略した場合には、全て同じものとしてマッピングされます。

逐次実行するプログラムブロック!$OMP PARALLEL!$OMP DO

マスタースレッド
スレーブスレッド

DO I = 1, N

並列実行するプログラムブロック

END DO!$OMP END DO!$OMP CRITICAL
一つのスレッドだけで順番に処理するブロック!$OMP END CRITICAL!$OMP DODO I = 1, N

並列実行するプログラムブロック

END DO!$OMP END DO!$OMP END PARALLEL
逐次実行するプログラムブロック

図 .18 クリティカルセクションの実行

26

インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

BARRIER 宣言子
BARRIER 宣言子は、全てのプロセスを同期させる為の指示を行います。個々のスレッドは、全てのスレッドがバリ
アポイントに到着するまでその後の実行を開始しません。全スレッドがバリアポイントに到達することにより同期がとれます。シンタックスは以下の通りです。

!$OMP BARRIERATOMIC 宣言子
ATOMIC 宣言子は、同時に複数のスレッドからアップデートされる可能性のあるメモリーエリアの更新を排他的に行います。

!$OMP ATOMIC
Expression-statement
このディレクティブは、ディレクティブに続く 1 行のステートメントだけに適用されます。ステートメントは以下のいずれかのフォームである必要があります。

x = x op expr, x = expr op x, x = intr (x, expr) , x = intr(expr, x)
x は組み込み関数で利用可能なデータ形式を持つスカラー変数で、expr は x を参照しない演算式となり、INTR
は MAX, MIN, IAND, IOR, IEOR のいずれかの組み込み関数、op は +, *, -, /, .AND., .OR., .EQV., .NEQV. のいず
れかの演算となります。
マスタースレッド
逐次実行するプログラムブロック!$OMP PARALLEL!$OMP DO

スレーブスレッド

DO I = 1, N

並列実行するプログラムブロック

END DO!$OMP END DO!$OMP ATOMIC
一つのスレッドだけで順番に処理するブロック!$OMP DODO I = 1, N

並列実行するプログラムブロック

END DO!$OMP END DO!$OMP END PARALLEL

逐次実行するプログラムブロック

x に対するロード、ストアが ATOMIC の対象となります。演算自身が ATOMIC の対象となるわけではありません。
CRITICAL 構文でもこの ATOMIC 構文と同じ処理が可能です。実際には、CRITICAL 構文の方が柔軟な排他制御が可能となります。
図 .19 ATOMIC アップデートの指定

27

インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

C$OMP PARALLEL PRIVATE(B)B = DOIT(I)C$OMP ATOMIC
X = X + FOO(B)
C$OMP END PARALLEL!$OMP PARALLEL PRIVATE(B, tmp)
B = DOIT(I)TMP = FOO(B)!$OMP CRITICAL
X = X + tmp!$OMP END CRITICAL!$OMP END PARALLEL
この 2 つの例では、共に X に対するアップデートを行っています。ATOMIC 構文による更新も CRITICAL 構文での更新も同じ機能を持ちますが、関数 foo の取り扱いがこの 2 つの定義では異なります。

FLUSH 宣言子
コンパイラーは、f l u s h が指定されたポイントで、スレッドの変数に関連する一貫性の保持のための共有変数に関する同期処理を指示します。

!$OMP FLUSH [(list)]
ここでの l i s t には、変数名をカンマ（,）で区切って指定します。省略すると以下の全ての共有変数について同期が取られます。
グローバル変数（COMMON ブロック、モジュールなど）

SAVE 属性のないローカル変数で、そのアドレスが他のサブプログラムへ引き渡されるなど、アドレスが参照される
ものSAVE 属性のないローカル変数で、サブプログラムにあるパラレル領域で SHARED と宣言されるもの
ダミーの引数全てのポインター参照

list には必要な変数をコンマ（,）
で区切って記述します。list の指定がない場合は全ての変数がフラッシュされます。
ORDERD ディレクティブ
ORDERD / END ORDERED で囲まれたコードブロックは、そのコードを逐次実行した場合と同様に実行されます。
!$OMP ORDERED

実行コードブロック!$OMP END ORDERED

ORDERED ディレクティブは DO または PARALLEL DO ディレクティブの内部だけに記述できます。また、その時、DO ディレクティブには ORDERED 宣言句も指定されている必要があります。

28

インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

REDUCTION 宣言句
REDUCTION 宣言句は、DO 構文と共に指定され REDUCTION 演算を並列処理するものです。
REDUCTION( {op| intr }: list )l i s t で指定された変数は組み込み関数で利用可能なデータ形式を持つスカラー変数と配列です。また、その変数のスコーピング属性は SHARED である必要があります。list で指定された変数はそれぞれのスレッドのためにプライベートのコピーが作成され、その値はオペレータの種類によって特定の値で初期化されます。intr は MAX, MIN,

IAND, IOR, IEOR のいずれかの組み込み関数が指定可能で、op は +, *, -, /, .AND., .OR., .EQV., .NEQV. のいず
れかの演算となります。

REDUCTION ループの後で共有のリダクション変数は、そのオリジナルの値とそれぞれのスレッドが持つプライベートのリダクション変数の最終値を使用して記述された o p の演算を行い、アップデートされます。リダクション演算は引き算を除き結合可能であるため、コンパイラーは最終値の計算について自由に再構成することができます。
共有変数の値は最初のスレッドが演算に到達すると未定義となり、リダクション演算が終了するまでその状態となります。通常、演算処理は REDUCTION 構文の最後で完了します。ただし、NOWAIT が指定された REDUCTION 構
文では、全てのスレッドがリダクション演算を終了したことを確認するために、B A R R I E R 同期を行うまでは共有変数の値は未定義のままとなります。

REDUCTION 宣言句は通常、次のようなワークシェアリング構文で使用されることを意図しています。
ASUM = 0.0
APROD = 1.0!$OMP PARALLEL DO REDUCTION(+:ASUM) REDUCTION(*:APROD)
DO I = 1, n
ASUM = ASUM + A(I)APROD = APROD * A(I)END DO!$OMP END PARALLEL DO
次のテーブルは、リダクションに指定可能な演算子および組み込み関数の一覧とその初期値を示しています。

演算子

初期値

演算子

初期値

+

0

.OR.

0

*

1

MAX

1

-

0

MIN

0

.AND.

全て 1

//

全て 1

表 .5 REDUCTION 演算

同じ種類の REDUCTION 宣言句には複数の変数を記述できます。異なった種類の REDUCTION 宣言句を指定する場合は、以下のように記述します!$OMP DO REDUCTION(+: A, Y) REDUCTION(.OR.: AM)

29

インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

5.5 その他の宣言句
IF 宣言句IF 宣言句は PARALLEL 構文に対して、
その構文を実行時に有効とするか無効とするかを指定するためのものです。
IF 宣言句の条件式が TRUE の場合のみ、並列実行構文が有効になり、並列実行がなされます。

NUM_THREADS 宣言句
NUM_THREADS 宣言句によって、PARALLEL 構文を処理するスレッド数を指定することが可能です。
NOWAIT 宣言句
OpenMP* の指示構文である END DO、END SECTIONS、END SINGLE の実行時には、並列実行領域のスレッ
ド全ての実行が終了するまで、各スレッドは待ち状態になります。N O W A I T 宣言句を指定した場合には、各スレッド
は待ち状態にならず次の処理を開始します。

逐次実行するプログラムブロック!$OMP PARALLEL!$OMP DO

マスタースレッド
スレーブスレッド

DO I = 1, N

並列実行するプログラムブロック

END DO!$OMP END DO!$OMP CRITICAL
一つのスレッドだけで順番に処理するブロック!$OMP END CRITICAL!$OMP DODO I = 1, N

並列実行するプログラムブロック

END DO!$OMP END DO!$OMP END PARALLEL
逐次実行するプログラムブロック

図 .20 NOWAIT 指定時のスレッド動作

N O W A I T は次の例のようにループ間の実行に依存性（ループ間でのデータの相互参照）がない場合に指定することで、並列実行の効率化を図ることが可能です。

!$OMP DODO J=1,N
A(J) = B(J) + C(J)END DO!$OMP DODO J=1,N
D(J) = E(J) * f
END DO!$OMP DODO J=1,nZ(J) = (A(J)+A(J+1)) * 0.5
END DO30

インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

5.6 ランタイム関数 / 環境変数
OpenMP* によるマルチスレッド・プログラミングの実行を行なう場合、環境変数によってプログラムの実行を制御することが可能です。

環境変数

説 明

OMP_NUM_THREADS

スレッド数の動的調整が有効になっている場合、環境変数の値は、使用するスレッドの数の上限として解釈されます。
例： setenv OMP_NUM_THREADS 4（Linux*）
set OMP_NUM_THREADS=4（Windows*）

OMP_SCHEDULE

環境変数のデフォルト値は、処理系に依存します。指定では、type[,chunk]の形式で指定し、type には、static/dynamic/guided が指定可能です。chunk の設定は、オプションです。
chunk が設定されていない場合には、static スケジュールの場合を除き、値 1 が使用されます。static スケジュールでは、デフォルトの chunk は、ループカウントを、
そのループに適用されるスレッドの数で割った値に設定されます。
例： setenv OMP_SCHEDULE "DYNAMIC"（Linux*）
set OMP_SCHEDULE=DYNAMIC（Windows*）

OMP_DYNAMIC

システ
値が true に設定されている場合、並列実行領域の実行に使用されるスレッドの数は、
ムのロードなどによって、システムが実行時に調整します。値が false に設定されていると、
この動的調整は無効になります。
例： setenv OMP_DYNAMIC TRUE（Linux*）
set OMP_DYNAMIC=TRUE（Windows*）

OMP_NESTED

ネストされた並列実行は有効になり、値が false に設定されて値が true に設定されていると、いると、ネストされた並列実行は無効になります。
デフォルト値は false です。
例： setenv OMP_NESTED TRUE（Linux*）
set OMP_NESTED=TRUE（Windows*）

表 .6 OpenMP* 環境変数31

インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

6 . OpenMP* の適用について
O penMP* によるマルチスレッド化は、プログラマーから並列処理を行うための様々な作業を解放します。以下の図に示すのは、簡単なプログラム開発、最適化、並列化の流れです。プログラムを自動並列化し性能評価ツールなどを使い、必要なところに OpenMP* 宣言子による並列処理の適用を行うというのが実際の開発の流れになります。

計算負荷の大きな関数やサブルーチンに対する自動並列処理や OpenMP* の適用の検討

プログラム開発者

プログラム
関数・サブルーチン

プログラム

OpenMP*

OpenMP* 宣言子の挿入による並列化指示
自動並列化
コンパイル
オプション

プログラム
OpenMP*

最適化オプション

インテル®
コンパイラー

コンパイル
オプション

インテル®
パフォーマンス
ツール

インテル®
コンパイラー

性能解析ツールによるパフォーマンス
チューニングマルチスレッド
実行モジュール

シングルスレッドでの最適化とプログラム性能の評価

インテル®
パフォーマンス
ツール

性能解析ツールによるパフォーマンス
チューニングマルチスレッド
実行モジュール

マルチスレッドでの最適化とプログラム性能の評価

図 .21 OpenMP* プログラムの開発フロー

プログラムの開発には、多くの試行錯誤とプログラムの実行と検証、デバッグといった作業が必要になります。またプログラムについては、その実行性能の向上を図るためのソースコードの書き換えなどを行う作業を、プログラムの開発中も開発後も行う必要があります。このような作業を効率良く、また短時間で行うには、優れた開発環境が必要です。インテルのソフトウェア製品は、マルチスレッド・プログラミングに対応したインテル ® コンパイラーでのプログラミン
グを支援する豊富なツール群が用意されています。それらのツールを活用することで、プログラム開発サイクルは、より充実したものになります。

OpenMP* 適用のためのステップは次のようになります。
1. インテル ® VTuneTM パフォーマンス・アナライザーを使いプログラムの動作の詳細な解析を行います。ホットスポッ
トを見つけることが並列処理では必要になります。

2. ホットスポットに対して OpenM P * 宣言子の適用などを検討します。データの依存関係などのために並列化できない部分などについては、依存関係の解消のために行うプログラムの変更を行います。この時、他のハイレベルの最適化手法（ソフトウエア・パイプラインやベクトル化）などに影響を与えるときがあります。この並列化による他のハイレベルの最適化の阻害は避ける必要があります。そのためには、並列化の適用時と非適用時の性能を比較検討する必要もあります。

3. 計算コアの部分について、もし可能であれば既にマルチスレッド向けに高度に最適化されているインテル ® マス・
カーネル・ライブラリー（MKL）などを積極的に利用することが並列処理の効率化を図る有効な手段です。これらのライブラリーのマルチスレッド化には O p e n M P * が使用されているので、容易に自動並列化に組み込むことが可
能です。

32

インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

7. おわりにプログラム開発者や研究者がプログラムを作るのは、そのプログラムの並列化を行う為ではありません。ある処理、解析を目的にプログラムを書き、そのプログラムをプラットフォームで効率良く、高速に実行できることを目的としています。これらのコンパイルツールは、開発者が本来のプログラムの開発目的である、これらのアルゴリズムの実装やロジックの検証のための作業に専念することを可能とし、並列化という必要ではありますが本質的ではない手間のかかる作業を開発者の代わりに担うものです。
パフォーマンスに対する高度の要求に答える形で、プロセッサーは高速化の一途をたどってきました。しかし、現在
プロセッサーとメモリーの性能格差が広がるにつれて、様々なアプリケーションにおいてメモリー・レイテンシーがパ
フォーマンスの面でのボトルネックになっています。また、プロセッサーの消費電力と発熱量も大きな問題です。このような状況を打破するためにも、デュアルコアとマルチコアといった最新のプロセッサーの実装技術が求められていこのような時代の要求に応えるものです。コンパイラーツールの更なる進化によって、ます。OpenMP* での並列化は、
今後、これらの機能はさらに強化されていきます。
様々なレベルでの並列処理において、それらの並列処理技術を緊密に結合することで、アプリケーションの性能を大幅に向上させることが可能です。

33

インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

付録 ̶ 自動並列処理と OpenMP*
次の性能データは、OpenMP* ホームページにある OpenMP* のサンプルプログラム md.f を OpenMP* で並列化したものと自動で並列化したものを比較したものです。

経過時間
50

40

■ OpenMP*30■ 自動並列化

20

10

0

1

2

4

プロセッサー数

SGI Altix システム / インテル ® Itanium® 2 プロセッサー 1.60GHz での計測結果

このケースでは自動並列化の効果は見られません。
実際のコンパイルでは、以下のように自動並列化によって、多くのループは並列化されています。

$

IFORT -O3 -PARALLEL -PAR_THRESHOLD0

md.f

md.f(35) : (COL. 6) REMARK: LOOP WAS AUTO-PARALLELIZED.
md.f(98) : (COL. 8) REMARK: LOOP WAS AUTO-PARALLELIZED.
md.f(161) : (COL. 6) REMARK: LOOP WAS AUTO-PARALLELIZED.
md.f(181) : (COL. 6) REMARK: LOOP WAS AUTO-PARALLELIZED.
md.f(212) : (COL. 6) REMARK: LOOP WAS AUTO-PARALLELIZED.
このコードでもっとも計算時間がかかるのは、以下のループです。このループの自動並列化は、サブルーチンの呼び出しなどもあり阻害されています。実際には、このループから呼び出されるサブルーチン dist 内のループなどは自動並列化されています。
しかし、
多重ループからの並列実行領域の呼び出しとなってしまうため並列効率を上げることは困難であり、逆にオーバーヘッ
ドが増えています。

34インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

96

DO I=1,NP

97! COMPUTE POTENTIAL ENERGY AND FORCES

98

F(1:ND,I) = 0.099

DO J=1,NP

100

IF (I .NE. J) THEN

101

CALL DIST(ND,BOX,POS(1,I),POS(1,J),RIJ,D)

102! ATTRIBUTE HALF OF THE POTENTIAL ENERGY TO PARTICLE 'J'

103

POT = POT + 0.5*V(D)104

DO K=1,ND

105

F(K,I) = F(K,I) - RIJ(K)*DV(D)/D

106

ENDDO

107

ENDIF

108

ENDDO

109

! COMPUTE KINETIC ENERGY110

KIN = KIN + DOTR8(ND,VEL(1,I),VEL(1,I))

111

ENDDO

148

SUBROUTINE DIST(ND,BOX,R1,R2,DR,D)

160

D = 0.0161

DO I=1,ND

162
163

DR(I) = R1(I) - R2(I)D = D + DR(i)**2.

164

ENDDO

165

D = SQRT(D)

166
167

RETURN

168

END

35

インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

このコードについては、以下のような OpenMP* 宣言子の指定が可能です。この指定によってサブルーチンの呼び出しを含めて、疎粒度での並列処理が可能となります。

!$OMP PARALLEL DO!$OMP& DEFAULT(SHARED)!$OMP& PRIVATE(I,J,K,RIJ,D)!$OMP& REDUCTION(+ : POT, KIN)
DO I=1,NP! COMPUTE POTENTIAL ENERGY AND FORCES
F(1:ND,I) = 0.0
DO J=1,NP
IF (I .NE. J) THENCALL DIST(ND,BOX,POS(1,I),POS(1,J),RIJ,D)! ATTRIBUTE HALF OF THE POTENTIAL ENERGY TO PARTICLE 'J'
POT = POT + 0.5*V(D)DO K=1,ND
F(K,I) = F(K,I) - RIJ(K)*DV(D)/D
ENDDO
ENDIF
ENDDO
! COMPUTE KINETIC ENERGYKIN = KIN + DOTR8(ND,VEL(1,I),VEL(1,I))
ENDDO!$OMP END PARALLEL DO
KIN = KIN*0.5*MASS
自動並列化は非常に容易なマルチスレッド・プログラミングのツールですが、ループレベルでの並列化の認識には限界がある
ことも事実です。自動並列化の内容を理解し、その上で OpenMP* をコンパイラーに対する並列化指示のためのツールとして使うことで、さらに効率の良い並列処理が可能となります。

36インテル® Fortran コンパイラー OpenMP* ガイド
デュアルコア / マルチコア対応アプリケーション開発 3

付録 ̶ OpenMP* サンプルプログラム

PROGRAM OMPINTEGER NUM_STEPSREAL*8 STEP,X,PI,SUM
NUM_STEPS = 10000000
STEP = 1.0D0 / DBLE(NUM_STEPS)
SUM = 0.0D0!$OMP PARALLEL DO REDUCTION(+:SUM)
PRIVATE(X)
DO I = 1, NUM_STEPS
X = (DBLE(I)-0.5D0)*STEP
SUM = SUM + 4.0D0 / (1.0D0+ X * X)END DOPI = STEP * SUMWRITE (6,*) 'PI = ',PI
END PROGRAM OMP

PROGRAM OMP
USE OMP_LIB
PARAMETER (NUM_THREADS=4)
INTEGER NUM_STEPSREAL*8
STEP,X,PI,SUM(0:NUM_THREADS-1)
NUM_STEPS = 10000000
STEP = 1.0D0 / DBLE(NUM_STEPS)CALL
OMP_SET_NUM_THREADS(NUM_THREADS)!$OMP PARALLEL PRIVATE(X)ID = OMP_GET_THREAD_NUM()
SUM(ID) = 0.0D0
ISTART = ID * NUM_STEPS /NUM_THREADS + 1
IEND = (ID+1) * NUM_STEPS /NUM_THREADSDO I = ISTART, IEND
X = (DBLE(I)-0.5D0)*STEP
SUM(ID) = SUM(ID) + 4.0D0 /(1.0D0 + X * X)
END DO!$OMP END PARALLEL
PI = 0.0D0
DO I = 0, NUM_THREADS-1
PI = PI + STEP * SUM(I)END DOWRITE (6,*) 'PI = ',PI
END PROGRAM OMP!$

37

本資料で言及されているインテル製品は、一般的な商業目的にのみ使用することを前提にしています。特定の目的に本製品を使用する場合、適合性の評価について
はお客様の責任になります。インテル製品は、医療、救命、延命措置、重要な制御または安全システム、核施設などの目的に使用することを前提としたものではありません。
分散並列処理、スーパー・コンピューターなどに関する各種情報は、インテル HPC リソース・センターをご参照ください。http://www.intel.co.jp/jp/go/hpc/

インテル株式会社〒 300-2635 茨城県つくば市東光台 5-6
http://www.intel.co.jp/
Intel、インテル、Intel ロゴ、Pentium、Xeon、Itanium、VTune は、アメリカ合衆国およびその他の国における Intel Corporation またはその子会社の商標または登録商標です。
* その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

©

2006 Intel Corporation. 無断での引用、転載を禁じます。

2006 年 5 月

527J-001
JPN/0605/PDF/SE/DEG/KS