10.2 共配列を用いたSPMDプログラミング [6.2]
10.2.1 概要
Fortran 2008には、“像”と呼ばれるプログラムの複数のコピーが並行して実行される、 SPMD(Single Program Multiple Data)プログラミングモデルが含まれています。 “共配列”という特別な変数が像同士の通信を容易にします。nAG Fortranコンパイラのリリース6.2では、実行が単一の像に制限されます。つまり、並列実行はありません。 今回のリリースでは、複数の像を正しく動作させる必要がある共配列プログラムは正常に実行できません。
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 FUNCTIONLOCK文が実行された時に像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= スカラ整数式
CRITICAL 構文:
[ construct-name : ] CRITICAL [ ( [ sync-stat-list ] ) ]
block
END CRITICAL [ construct-name ]
ノート: 省略可能な括弧とsync-stat-listは、Fortran 2018の機能です。
block に以下を含むことは許されていません:
- RETURN文もしくはSTOP文
- 像制御文
- 飛び先が構文の外である分岐
FAIL IMAGE文:
FAIL IMAGE
ノート: この文はFortran 2018です。LOCK文:
LOCK ( lock-variable [ , lock-stat-list ] )
ここでlock-stat-listは以下のうち一つ以上をカンマで区切ったリストです。
ACQUIRED_LOCK = スカラ論理変数
ERRMSG = スカラ基本文字変数
STAT = スカラ整数変数
SYNC ALL文:
SYNC ALL [ ( [ sync-stat-list ] ) ]
SYNC IMAGES文:
SYNC IMAGES ( image-set [ , sync-stat-list ] )
ここでimage-setはアスタリスク、もしくはスカラか1次元の整数式です。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桁以上の指数範囲を持つ必要があります。 また共添字付きであってはなりません。
ノート: STATはFortran 2018の一部です。
SUBROUTINE ATOMIC_REF(VALUE, ATOM, STAT)
- VALUE
- はATOMと同じ型でINTENT(OUT)のスカラです。
- ATOM
- は種別がINTEGER(ATOMIC_INT_KIND)もしくはLOGICAL(ATOMIC_LOGICAL_KIND)のスカラで、 共配列もしくは共添字付き実体でなければなりません
- STAT
- (省略可能) は整数スカラで、十進4桁以上の指数範囲を持つ必要があります。 また共添字付きであってはなりません。
ノート: STATはFortran 2018の一部です。
INTEGER FUNCTION IMAGE_INDEX(COARRAY, SUB)
- COARRAY
- 共配列(どの型でも良い)
- SUB
- 大きさがCOARRAYの共次元数と同じ整数ベクトル
FUNCTION LCOBOUND(COARRAY, DIM , KIND)
- COARRAY
- 共次元数N;の共配列(どの型でも良い)
- DIM
- (省略可能) 1 から N;の範囲のスカラ整数
- KIND
- (省略可能) スカラ整数定数式
- 結果
- IntegerもしくはInteger(Kind=KIND)
SUBROUTINE MOVE_ALLOC(FROM, TO, STAT, ERRMSG) ! 更新された
- FROM
- 割付け変数(どの型でも良い)
- TO
- FROMと同じ宣言型、型パラメタ、次元数、及び共次元数を持つ割付け
- STAT
- INTENT(OUT) 4桁以上の十進指数範囲を持つスカラ整数
- ERRMSG
- INTENT(INOUT) スカラ基本文字変数
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
- スカラ整数
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]は有効ではないのですが)有効だからです。