10.2 共配列を用いたSPMDプログラミング [6.2, 7.0]
10.2.1 概要
Fortran 2008には、“像”と呼ばれるプログラムの複数のコピーが並行して実行される、 SPMD(Single Program Multiple Data)プログラミングモデルが含まれています。 “共配列”という特別な変数が像同士の通信を容易にします。nAG Fortranコンパイラのリリース6.2では、実行が単一の像に制限されます。つまり、並列実行はありません。 nAG Fortranコンパイラのリリース7.0では、Co-SMPテクノロジーを使用して、SMPマシン上で複数の像を並行で実行できます。
10.2.2 像
各像には、それぞれ独自の変数と入出力単位が含まれています。 実行時の像の数は、プログラムによって決まるのではなく、コンパイラ固有の方法によって決まります。 実行中の像の数は固定で、像を作成したり破棄することはできません。 組み込み関数NUM_IMAGES()
は、像の数を返します。
各像には“image index”があり、これは1から像の数までの正の整数です。
組み込み関数THIS_IMAGE()
は、実行中の像の像番号を返します。
10.2.3 共配列
共配列は別の像が直接アクセスできる変数で、ALLOCATABLE
またはSAVE
属性を持っているか、もしくは仮引数でなければなりません。
共配列には“共次元数”があり、これは“共次元”の数を示します。
それぞれの共次元は共下限と共上限を持ち、“共形状”を決定します。
最後の共次元の共上限は“*
”で、大きさ引継ぎ配列に似ています。
“共添字”は、配列の添字が配列要素番号を決定するのと同じように、参照する像番号を決定します。
ここでも、大きさ引継ぎ配列のように、像番号は像の数以下でなければなりません。
共配列は、スカラまたは配列にすることができます。
POINTER
属性を持つことはできませんが、ポインタ成分を持つことができます。
変数だけでなく共配列成分も可能です。この場合、成分はALLOCATABLE
共配列でなければなりません。
またそのような成分を持つ変数は、仮引数であるかもしくはSAVE
属性を持っていなければなりません。
10.2.4 共配列の宣言
共配列はcoarray-specを持ちます。 これは、変数名の後に大括弧で囲まれて宣言されるかもしくはCODIMENSION
属性または文として宣言されます。
例えば
REAL a[100,*] REAL,CODIMENSION[-10:10,-10:*] :: b CODIMENSION c[*]上記コードは、共配列Aの共次元数が2で、それぞれの共次元の共下限が1で第一共次元の共上限が100であること、 共配列Bの共次元数が2で、それぞれの共次元の共下限が-10で第一共次元の共上限が10であること、 更に共配列Cの共次元数が1で、共次元の共下限が1であることを宣言しています。 割付け可能ではない共配列の場合、coarray-specで最後の共次元は、像の数に依存するため、 アスタリスクで宣言しなければならない事に注意して下さい。
ALLOCATABLE
な共配列はdeferred-coshape-specで宣言されます。例えば、
REAL,ALLOCATABLE :: d[:,:,:,:]は
D
の共次元数が4であることを宣言します。
10.2.5 別の像の共配列へのアクセス
別の像の共配列のコピーにアクセスするには、共配列名に続く角括弧内に共添字を指定します。 これは“共添字付き”と呼ばれ、そのようなオブジェクトは共添え字付き実体です。 例えば、以下のような場合REAL,SAVE :: e[*]共添え字付き実体
e[1]
は像1のE
のコピーを参照し、
e[13]
は像13のE
のコピーを参照します。
もう少し複雑な例を以下に示します。
REAL,SAVE :: f[10,21:30,0:*]
f[3,22,1]
は像113のF
のコピーを参照します。
像番号とコンピュータのどのトポロジとの間にも相関はありませんので、
複雑な共次元(特に別の共形状を持つ共配列の利用)は避けるべきです。
共配列が配列の場合、共添え字を配列名の直後に指定することはできません。 その代わりに部分配列の表記を使います。 例えば、
REAL,SAVE :: g(10,10)[*]において
g[inum]
の参照は無効です。像INUM
でG
の配列全体を参照する場合には
g(:,:)[inum]
を使います。
同様にG
の単一成分をアクセスする場合、共添え字が添え字の後に続くようにします。例)
g(i,j)[inum]
最後に、共配列がアクセスされる場合(自体の像からの場合ももリモートからの場合も)、 セグメント順序付けルール(次のセクションを参照)に従わなければならないことに注意してください。 これは、データ競争に関するナンセンスな状況を避けるためです。
10.2.6 セグメントと同期
それぞれの像の実行は“像制御文”によりセグメントに分割されます。 単一の像のセグメントは順序付けされます: 各セグメントは前のセグメントに続きます。 異なる像のセグメントは、同期によって、一方が他方に続くように、順序付けできます。 それ以外の場合は順不同となります。共配列が像Iのセグメント内で定義されている(値が割り当てられている)場合、 別の像Jは、Iのセグメントに続くセグメント内でしか参照または定義することができません。
像制御文及びそれらの同期効果は以下の通りです。
SYNC ALL
- 他の像の対応する
SYNC ALL
文と同期します。 1つの像のSYNC ALL
文のn番目の実行に続くセグメントは、 他のすべての像のSYNC ALL
文のn番目の実行に先行するすべてのセグメントに続きます。 SYNC IMAGES (
list)
- list(整数式でスカラもしくはベクトル)内の像に対する対応する
SYNC IMAGES
文の実行と同期します。 呼び出す側の像番号をlistに含めても何の効果もありません。 listに像番号Jを持つ像IのSYNC IMAGES
文のn番目の実行に続くセグメントは、 listに像Iを持つSYNC IMAGES
のn番目の実行より先に像Jのセグメントに続きます。 SYNC IMAGES (*)
- listに全ての像番号が含まれる場合の
SYNC IMAGES
と同等。例)SYNC IMAGES ([(i,i=1,NUM_IMAGES())])
SYNC MEMORY
- 他の像と同期することなくセグメント分割器としてのみ機能します。 同期のために他の何らかのメカニズムが使用されている時に、ユーザー定義の順序付けに役立つ場合があります。
ALLOCATE
もしくはDEALLOCATE
- (割付け、もしくは解放が行われる共配列実体が伴った場合)
同じ
ALLOCATE
もしくはDEALLOCATE
を実行する必要があるすべての像が同期されます。 CRITICAL
及びEND CRITICAL
- 一度に1つの像でのみ
CRITICAL
構文を実行できます。CRITICAL
構文内のコードはセグメントを形成します。 このセグメントはCRITICAL
構文の前回の実行(どの像でも)に続きます。 LOCK
及びUNLOCK
- 特定のロック変数をロックする
LOCK
文に続くセグメントはその変数を以前にアンロックしたUNLOCK
文に続きます。 END
文- 局所
ALLOCATABLE
配列の自動割付けを解除するEND BLOCK
文、END FUNCTION
文、またはEND SUBROUTINE
文は、 すべての像と同期します。(同じEND
文を実行する必要がある) MOVE_ALLOC
組込み- 共配列引数を伴って組込みサブルーチン
MOVE_ALLOC
を実行すると、全ての像が同期されます。 その際に同じCALL
文を実行する必要があります。
像制御文には副作用があるので、純粋な手続きやDO CONCURRENT
構文内では許可されていないことに注意してください。
10.2.7 共配列の割付け及び解放
ALLOCATABLE
配列の割付けを行う場合、ALLOCATE
文で共上下限を指定する必要があります。例)
REAL,ALLOCATABLE :: x(:,:,:)[:,:] ... ALLOCATE(x(100,100,3)[1:10,*])最後の共上限はアスタリスクでなければならないことに注意してください。 これは、明示並列形共配列を宣言する時と同じです。
共配列の割付けを行う時には同期が行われます。すべての像が同じALLOCATE
文を実行し、
全ての像の共配列のすべての上下限、型パラメタ、および共上下限は同じでなければなりません。
同様に、DEALLOCATE
文もしくはEND
文の自動割付け解除によって共配列の割付けが解除された時に同期が行われます。
全ての像が同じ文を実行しなければなりません。
組込み代入文による割付け可能変数の通常の自動再割付け(例えば配列の形状が異なる場合)は、 共配列では使用できないことに注意してください。 代入される割付け可能な共配列変数はあらかじめ割付け済みで式と適合している必要があります。 また、無指定型パラメタを伴う場合には一致している必要があります。 更に、多相的である場合には動的型が一致している必要があります。
10.2.8 Critical構文
これは、一度に1つのイメージだけがコードセグメントを実行するようにするメカニズムを提供します。CRITICAL
構文は一度に1つの像のコードセグメントだけが実行されるための機能を提供します。
例)
CRITICAL ...do something END CRITICAL像Jが構文のブロックを実行している間に像IがCRITICALステートメントに到着した場合、 像Iは次に進む前に、像Jが
END CRITICAL
文を実行するのを待ちます。
したがって、像IのCRITICAL
— END CRITICAL
セグメントは、
像Jの同等なセグメントに続きます。
例えば構文として以下のような名前を持っている事もあります。
critsec: CRITICAL ... END CRITICAL critsec名前は構文の機能には何ら影響を与えません。 それぞれの
CRITICAL
構文は他のすべての構文とは別個のものでそれらの実行に影響されません。
10.2.9 ロック変数
“ロック変数”は、組込みモジュールISO_FORTRAN_ENV
で定義されるLOCK_TYPE
型の変数です。
ロック変数は、共配列または共配列の成分でなければなりません。最初は“UNLOCK”状態です。
LOCK
文の実行によってロックされ、
UNLOCK
文の実行によってロックが解除されます。
これらの文を除き、変数の定義に(INTENT(INOUT)
の仮引数を除き)ロック変数は使えません。
LOCK
文のロックが成功した後のセグメントの実行は、
ロックが解除された像のUNLOCK
文の前のセグメントの実行に続きます。
例)
INTEGER FUNCTION get_sequence_number() USE iso_fortran_env INTEGER :: number = 0 TYPE(lock_type) lock[*] LOCK(lock[1]) number = number + 1 get_sequence_number = number UNLOCK(lock[1]) END FUNCTION
LOCK
文が実行された時に像1の変数lock
がロックされている場合、
ロックが解除されるのを待ってから実行が継続されます。
従って、関数get_sequence_number()
は一方向の順序関係を提供します。
値Nを返す呼び出しの後のセグメントは、
呼び出し前のNより小さい値を返したすべてのセグメントに続きます。
条件付きロックの機能は、ACQUIRED_LOCK=
指定子で提供されます。
ACQUIRED_LOCK=
指定子が存在する場合、
実行中の像は、以前にロックが解除されていた場合にのみロックを取得します。
例)
LOGICAL gotit LOCK(lock[1],ACQUIRED_LOCK=gotit) IF (gotit) THEN ! We have the lock. ELSE ! We do not have the lock - some other image does. END IF
像が既にその像にロック済の変数のLOCK
を試みたり、
既にロックが解除されているかもしくは他の像にロック済の変数のUNLOCK
を試みたりすることはエラーです。
STAT=
指定子が使用されている場合、これらのエラーはそれぞれSTAT_LOCKED
、
STAT_UNLOCKED
、STAT_LOCKED_OTHER_IMAGE
の値を返します。
(これらの名前付き定数は、組み込みモジュールISO_FORTRAN_ENVで提供されている)
10.2.10 アトミックな共配列のアクセス
セグメント順序のルールの例外で、整数種別がATOMIC_INT_KIND
、
または論理種別がATOMIC_LOGICAL_KIND
の共配列は、
組込みサブルーチンATOMIC_DEFINE
で定義する、
あるいは組込みサブルーチンATOMIC_REF
で参照する事が可能です。
例)
MODULE stopping USE iso_fortran_env LOGICAL(atomic_logical_kind),PRIVATE :: stop_flag[*] = .FALSE. CONTAINS SUBROUTINE make_it_stop CALL atomic_define(stop_flag[1],.TRUE._atomic_logical_kind) END SUBROUTINE LOGICAL FUNCTION please_stop() CALL atomic_ref(please_stop,stop_flag[1]) END FUNCTION END MODULEこの例が示すとおり、セグメントについて一切考慮せずに、任意の像が
make_it_stop
を呼び出し、
他の像がplease_stop()
関数を呼び出す事に、全く問題はありません。
(分散メモリー・マシンでは、アトミック変数への変更が他の像で見えるようになるのに時間がかかるかもしれませんが、
最終的には伝わります。)
通常の代入と参照は常にセグメント順序付けルールの対象となるため、 アトミックサブルーチンへの呼び出しと混在させてはならないことに注意してください。
10.2.11 実行の正常終了
像がSTOP
文またはEND PROGRAM
文を実行すると、正常終了が開始されます。
他の像は継続実行されます。停止された像の全てのデータはそのまま保持され、
その像の共配列は他の像から引き続き参照及び定義できます。
正常終了の処理がすべての像で開始されると、プログラムが終了します。
10.2.12 エラー終了
IOSTAT=
指定子やERR=
指定子を持たない入出力文のI/Oエラーなど、
エラーによっていずれかの像が終了すると、プログラム全体がエラー終了します。
分散メモリー・マシンでは、全ての像に終了メッセージが届くのに時間がかかる可能性もあり、
終了が即時ではない可能性もあります。
ERROR STOP
文はエラー終了を開始します。
10.2.13 フォールトトレランス
Fortran 2018標準には、像の障害の検出、シミュレート、回復するための多くの機能が追加されています。 例えば、FAIL IMAGE
文は、実行中の像が失敗(他の像からのアクセスに対して応答を停止)するようにします。
これらの拡張は、Fortran 2008の機能ではありませんが、詳細を以下に示します。
FAIL IMAGE
文そのものは、像の数が1の時にはそれほど有用ではありません。
それは必然的にプログラムの完全な失敗を引き起こすからです。
10.2.14 共配列の機能詳細
共添字付き実体(データ実体特定子)
データ実体指定子では、共配列である部品(成分また基底実体)は、像選択子(image selector)を含むことができます。
part-name [ (
section-subscript-list )
] [ image-selector ]
left-bracket cosubscript-list [,
image-selector-spec ] right-bracket
cosubscript(共添え字)の数はpart-nameの共次元数と等しくなければなりません。 image-selectorが指定され、part-nameが配列の場合は、 section-subscript-listも合わせて指定する必要があります。 省略可能なimage-selector-specはFortran 2018(フォールトトレランス機能の一部)であり、 以下に示す指定子を一つ以上コンマ区切りにしたリストです。
STAT=
スカラ整数変数
TEAM=
像のチームの値
TEAM_NUMBER=
スカラ整数式
ISO_FORTRAN_ENV
のTEAM_TYPE
型のスカラー式でなければなりません。
STAT=
変数には、参照または定義が成功した場合には0、
参照される像が失敗した場合はSTAT_FAILED
という値が割り当てられます。
CRITICAL
構文:
[ construct-name :
] CRITICAL
[ (
[ sync-stat-list ] )
]
block
END CRITICAL
[ construct-name ]
STAT=
指定子、ERRMSG=
指定子、
もしくはその両方(カンマで区切られたもの)です。
ノート: 省略可能な括弧とsync-stat-listは、Fortran 2018の機能です。
block に以下を含むことは許されていません:
-
RETURN
文もしくはSTOP
文 - 像制御文
- 飛び先が構文の外である分岐
FAIL IMAGE
文:
FAIL IMAGE
LOCK
文:
LOCK (
lock-variable [,
lock-stat-list ] )
ACQUIRED_LOCK =
スカラ論理変数
ERRMSG =
スカラ基本文字変数
STAT =
スカラ整数変数
ISO_FORTRAN_ENV
のLOCK_TYPE
型のスカラ変数です。
SYNC ALL
文:
SYNC ALL
[ (
[ sync-stat-list ] )
]
SYNC IMAGES
文:
SYNC IMAGES (
image-set [,
sync-stat-list ] )
SYNC MEMORY
文:
SYNC MEMORY
[ (
[ sync-stat-list ] )
]
UNLOCK
文:
UNLOCK (
lock-variable [,
sync-stat-list ] )
ノート:
- sync-stat-listやlock-stat-listの変数は、 共添え字を持つ実体であってはなりません。 また、文の他の何かに依存していてはなりません。
10.2.15 組込み手続きと共配列
SUBROUTINE ATOMIC_DEFINE(ATOM, VALUE, STAT)
ATOM
- は種別が
INTEGER(ATOMIC_INT_KIND)
もしくはLOGICAL(ATOMIC_LOGICAL_KIND)
のINTENT(OUT)
のスカラで、共配列もしくは共添字付き実体でなければなりません。 VALUE
- は
ATOM
と同じ型のスカラです。 STAT
- (省略可能) は整数スカラで、十進4桁以上の指数範囲を持つ必要があります。 また共添字付きであってはなりません。
ATOM
には(セグメントのルールに関わりなく)VALUE
の値がアトミックに代入されます。
STAT
が存在する場合、エラーが発生した場合に正の値が代入され、そうでない場合はゼロが代入されます。
ノート:
STAT
はFortran 2018の一部です。
SUBROUTINE ATOMIC_REF(VALUE, ATOM, STAT)
VALUE
- は
ATOM
と同じ型でINTENT(OUT)
のスカラです。 ATOM
- は種別が
INTEGER(ATOMIC_INT_KIND)
もしくはLOGICAL(ATOMIC_LOGICAL_KIND)
のスカラで、 共配列もしくは共添字付き実体でなければなりません STAT
- (省略可能) は整数スカラで、十進4桁以上の指数範囲を持つ必要があります。 また共添字付きであってはなりません。
ATOM
の値は(セグメントのルールに関わりなく)アトミックに読まれ、
変数VALUE
に代入されます。
STAT
が存在する場合、エラーが発生した場合に正の値が代入され、そうでない場合はゼロが代入されます。
ノート:
STAT
はFortran 2018の一部です。
INTEGER FUNCTION IMAGE_INDEX(COARRAY, SUB)
COARRAY
- 共配列(どの型でも良い)
SUB
- 大きさが
COARRAY
の共次元数と同じ整数ベクトル
SUB
の値がCOARRAY
の有効な共添え字である場合
結果の値は参照される像の像番号となり、そうでない場合には結果はゼロとなります。
例えばX
が共上下限[11:20,13:*]
で宣言された場合、
IMAGE_INDEX(X,[11,13])
の結果は1となり、 IMAGE_INDEX(x,[1,1])
の結果はゼロとなります。
FUNCTION LCOBOUND(COARRAY, DIM , KIND)
COARRAY
- 共次元数N;の共配列(どの型でも良い)
DIM
- (省略可能) 1 から N;の範囲のスカラ整数
KIND
- (省略可能) スカラ整数定数式
- 結果
- IntegerもしくはInteger(Kind=KIND)
DIM
が出現した場合、結果はスカラでCOARRAY
の共次元の共下限の値です。
DIM
が出現しない場合、結果は長さNのベクトルでCOARRAY
の全ての共下限を含みます。
DIM
の実引数はそれ自身が省略可能な仮引数であってはなりません。
SUBROUTINE MOVE_ALLOC(FROM, TO, STAT, ERRMSG) ! 更新された
FROM
- 割付け変数(どの型でも良い)
TO
FROM
と同じ宣言型、型パラメタ、次元数、及び共次元数を持つ割付けSTAT
INTENT(OUT)
4桁以上の十進指数範囲を持つスカラ整数ERRMSG
INTENT(INOUT)
スカラ基本文字変数
FROM
及びTO
が共配列の場合、CALL
文は全ての像を同期させる像制御文です。
STAT
が存在する場合、エラー発生時には正の値が代入され、それ以外ではゼロが代入されます。
ERRMSG
が存在する場合でエラーが発生すると、説明メッセージが代入されます。
ノート: STAT
及びERRMSG
引数はFortran 2018です。
INTEGER FUNCTION NUM_IMAGES()この組込み関数は像の数を返します。 nAG Fortran Compilerの本リリースでは常に1となります。
INTEGER FUNCTION THIS_IMAGE()実行されている像の像番号を返します。
FUNCTION THIS_IMAGE(COARRAY)
COARRAY
の共次元数と同じ大きさの基本種別の整数型の配列を返します。
(型を問わず共配列であっても良い)
返される値は実行されている像に対応するCOARRAY
の共添え字です。
INTEGER FUNCTION THIS_IMAGE(COARRAY, DIM)
COARRAY
- 共配列(どの型であっても良い)
DIM
- スカラ整数
DIM
の共添え字を返します。
ノート: Fortran 2008ではDIM
が省略可能な仮引数であってはなりませんでしたが、
Fortran 2018では許されるようになりました。
FUNCTION UCOBOUND(COARRAY, DIM, KIND)
COARRAY
- 共次元数がN;の共配列(どの型であっても良い)
DIM
- (省略可能) 1からN;の範囲のスカラ整数
KIND
- (省略可能) スカラ整数定数式
- Result
- Integer もしくは Integer(Kind=KIND).
DIM
が出現した場合、結果はスカラでCOARRAY
の共次元の共上限の値です。
DIM
が出現しない場合、結果は長さNのベクトルでCOARRAY
の全ての共上限を含みます。
DIM
の実引数はそれ自身が省略可能な仮引数であってはなりません。
COARRAY
の共次元数がN>1である場合で、
現在の実行の像の数がN−1以下の共寸法の整数倍でない場合、
像は完全な長方形とはなりません。
このような場合、最後の共上限の値は共添え字が共次元として取ることができる最大の値となります。
例)共配列の仕様[1:3,1:*]
で4つの像が実行中である場合、
最後の共上限は2となります。これは共添え字[1,2]
が
([2,2]
と[2,3]
は有効ではないのですが)有効だからです。