MPC++ マルチスレッドテンプレートライブラリ


概要

このドキュメントでは MPC++ マルチスレッドテンプレートライブラリと呼ばれる、MPC++ で複数スレッドプログラミングを行うための C++ テンプレートライブラリについて記述しています。この中には、 i) 同期および非同期にローカル/リモートスレッドの呼び出しに使われる invoke および ainvoke 関数テンプレート、 ii) スレッド間の同期および通信に使われる Sync クラステンプレート、 iii) リモートメモリへを指すための GlobalPtr クラステンプレート、 iv) リダクション用の Reduction クラステンプレート、 v) バリア同期用の Barrier クラス、および vi) スレッドの実行を一時停止し、他のスレッドに実行を移すための yield 関数 が含まれています。

目次

  1. はじめに
  2. プログラミングモデル
    1. スレッド実行一時停止のタイミング
  3. 関数インスタンス
    1. 同期関数インスタンス呼び出し
    2. 非同期関数インスタンス呼び出し
    3. 制限事項
  4. 同期機構
    1. その他のオペレーション
    2. Read オペレーション
    3. Peek オペレーション
    4. Write オペレーション
    5. Queue Length オペレーション
  5. グローバルポインタ
    1. 配列へのグローバルポインタ
    2. グローバルポインタへのグローバルポインタ
    3. グローバルオブジェクト呼び出し
    4. リモートメモリアドレス
    5. 可変長リモートメモリ操作
  6. グローバル同期
    1. バリア
    2. リダクション
  7. その他の関数
    1. スレッド実行コントロール
    2. リモートオブジェクトの割り当て/解放
  8. 参考文献
  9. ライブラリ概要
    1. invoke 関数テンプレート
      1. 返り値を持つ関数
      2. Void 型関数
      3. 返り値を持つグローバルオブジェクトメンバ関数
      4. グローバルオブジェクト Void メンバ関数
    2. ainvoke 関数テンプレート
      1. 返り値を持つ関数
      2. Void 型関数
      3. 返り値を持つグローバルオブジェクトメンバ関数
      4. グローバルオブジェクト Void メンバ関数
    3. Sync クラステンプレート
    4. GlobalPtr クラステンプレート
    5. Barrier および Reduction クラス
    6. その他

1 はじめに

C++ の拡張である MPC++ バージョン 1,0 は 並列/分散プログラミング[2] のために設計されました。いくつかの言語拡張を設定する代わりに、我々は拡張・変更の可能なプログラミング言語システムの実現のために低レベル並列記述プリミティブと MPC++ メタレベルアーキテクチャ [3] を設計しました。データパラレルステートメントや分散アクティブオブジェクトなどの高度な並列/分散構造が拡張可能な特徴を利用して実装されています。

並列記述プリミティブは マルチスレッド およびメッセージドリブン実行をサポートする超並列マシン RWC-1 上でシステムプログラミング言語を作るために設計されました。これらのプリミティブは i) メッセージパッシングによるスレッド呼び出しのアブストラクションである ''関数インスタンス'' と ii) スレッド間通信のアブストラクションである ''メッセージエントリ'' および ''トークン'' です。プリミティブはメタレベルアーキテクチャを使用して言語拡張として実現されています。

MPC++ バージョン 2.0 は二つのレベル、レベル 0 およびレベル 1 で設計されています。レベル 0 は C++ のテンプレート機能を用いて言語拡張を加えることなく実現された MPC++ の基本的並列実行モデルを定義する並列記述プリミティブについて規定しています。レベル 1 は MPC++ のメタレベルアーキテクチャとアプリケーションごとの拡張について規定しています。

このドキュメントでは、MPC++ マルチスレッドテンプレートライブラリ (MTTL) と呼ばれるレベル 0 並列記述プリミティブについて記述しています。この中には i) 同期および非同期ローカル/リモートスレッド呼び出しに使われる invoke および ainvoke 関数テンプレート、 ii) スレッド間の同期および通信に使われる Sync クラステンプレート、 iii) リモートメモリを指すのに使われる GlobalPtr クラステンプレート、および iv) スレッドの実行を一時停止し、他のスレッドに実行を渡す yield 関数 が含まれています。

2 プログラミングモデル

プログラム、プロセス、およびスレッド:

MPC++ プログラム は分散メモリにもとづく並列システム上での実行を想定しています。プログラムコードは全ての物理プロセッサに分散され、プログラムの プロセス が各プロセッサ上で動作します。各プロセスは プリエンプトされない いくつかの制御スレッドを持っています。すなわち、スレッドの実行は同期待ちをしたり終了したりするまで続きます。詳細な スレッド実行一時停止のタイミング については後で述べます。プログラムはローカルもしくはリモートの、制御スレッドを持つ関数インスタンスを呼び出します。関数インスタンスの呼び出しは新しいスレッドの生成と関数の実行を含んでいます。関数インスタンスを呼び出したプログラムは呼び出された関数インスタンスの実行が終わるまでブロックされます。

変数:

すべての 変数 はプロセッサごとにローカルです。ファイルスコープで定義されている変数は各プロセッサ毎に割り当てられます。このような変数がプロセッサから参照された場合、ローカルのメモリ空間がアクセスされます。変数 myPE および peNum があらかじめ定義されており、それぞれプロセッサ番号とプロセッサの数を表します。プロセッサ番号は 0 から始まって peNum - 1 までとなります。

初期化:

mpcxx_initialize 関数が MPC++ の初期化を行います。この関数はメインルーチンの先頭で呼ばれなければなりません。メインルーチンはファイルスコープ変数の初期化後に、プロセッサ 0 上でのみ呼び出されます。他のプロセッサは各々のファイルスコープ変数を初期化した後、メッセージ待ちの状態になります。

同期および通信:

Sync と呼ばれる同期構造が、複数 reader/writer 通信モデルを実現するためにサポートされています。これは FIFO 通信バッファ のように振る舞います。reader が Sync オブジェクトからデータを読もうとしたときにまだデータが得られない場合、writer がデータを Sync オブジェクトに書き込むまでブロックされます。reader がデータを読むと、そのデータは取り除かれます。reader はデータが取り除かれることなくデータを読むこともできます。writer がいくつものデータを書き込んだ場合、これらのデータは Sync オブジェクト中のキューに入れられます。

グローバルポインタ:

プログラムは任意のリモートオブジェクトのメンバ関数インスタンスを呼び出せるのと同様に、任意のリモートデータを グローバルポインタ を介してアクセスすることができます。オブジェクトのいくつかの関数インスタンスが呼び出されえます。複数の関数インスタンスが同時に呼ばれた場合の制御についてはプログラマの責任となります。Actor モデルなどの並列オブジェクトモデルは定義していません。このようなプログラミング機構は言語拡張部分である MPC++ レベル 1 で定義されます。

実行順序:

あるプロセッサ上でのリモート関数呼び出し操作の順序は、それらの処理をリモートプロセッサ上で行うときにも維持されます。あるプロセッサ上でのグローバルポインタを用いたリモートメモリ操作の順序は、それらの処理をリモートプロセッサ上で行うときにも維持されます。しかし、リモート関数インスタンス呼び出しとリモートメモリ操作との順番は維持されません。プログラマは、リモートメモリ操作の後にリモート関数インスタンスを呼び出す場合の順序が維持されることを想定してもよいですが、この逆の順番の場合では想定してはなりません。言い換えると、リモートマシン上でのリモートメモリ操作はリモート関数インスタンス呼び出しの実行より前に行われる場合があります。

2.1 スレッド実行一時停止のタイミング

スレッドの実行は次のような場合に一時停止されますが、プログラマはこれらの場合が起こることを仮定したプログラムを書いてはなりません:

  1. Sync オブジェクト の値を読む
  2. リモート関数インスタンス を同期的に呼び出す
  3. グローバルポインタ を介してデータを読む

無限ループがプログラムされてしまった場合、他のスレッドや他のプロセッサから要求されたリモートメモリ操作は処理されなくなってしまいます。関数 yield() が現在のスレッドの実行を一時停止して他のスレッドに切り替えるために提供されています。

3 関数インスタンス

3.1 同期関数インスタンス呼び出し

invoke 関数テンプレート は、関数インスタンスをローカルまたはリモートに呼び出しリターンメッセージを受け取るまでスレッドの実行を ブロック できるようにします。この関数インスタンス呼び出しには新しいスレッドの生成とスレッドのコンテキスト切り替えが含まれています。プログラマは他のスレッドに実行を移すために関数インスタンスをローカルに呼び出します。

invoke 関数テンプレートは、返り値を持つ関数 用と Void 型関数 用の二つの書式を持っています。下に示すように、前者の invoke の書式は i) 返り値が収められる変数、 ii) 関数インスタンスの呼び出されるプロセッサ番号、 iii) 関数名、および iv) 関数の引数 をとります。後者の invoke の書式は i) 関数インスタンスの呼び出されるプロセッサ番号、 ii) 関数名、および iii) 関数の引数 をとります。

function-instance-invocation:
invoke( variable, processor-number, function-name, arguments )
invoke( processor-number, function-name, arguments )
processor-name:
integral-value
intergral-variable
function-name:
identifier
arguments:
c++-function-arguments

次の例は foo 関数インスタンスがプロセッサ 1 上で呼び出される様子を示しています。メインスレッドの実行は foo 関数の実行が終わるまでブロックします。foo 関数の実行が終わると、返り値が変数 i に収められメインスレッドの実行が再開されます。10 行目では void 型関数インスタンスがプロセッサ 2 上で呼び出されています。bar 関数の実行が終了すると、メインスレッドの実行が再開されます。

 1 #include <mpcxx.h> 
 2 int foo(int, int); 
 3 void bar(int, int); 
 4 main(int argc, char **argv) 
 5 {
 6 	int i; 
 7 
 8      mpcxx_initialize(argc, argv);
 9 	invoke(i, 1, foo, 1, 2); 
10 	invoke(2, bar, 10, 20); 
11 }

3.2 非同期関数インスタンス呼び出し

非同期関数インスタンス呼び出しは、スレッドが関数インスタンスを呼び出し、ブロックされることなく プログラムの続きを実行する、ということを意味します。スレッドは後で同期機構を用いて返り値を得ます。ainvoke 関数テンプレート が非同期関数インスタンス呼び出しをプログラムするために提供されています。

ainvoke 関数テンプレートには、返り値を持つ関数 用と void 型関数 用の二つの書式があります。下に示すように、一番目の ainvoke の書式は i) 関数からの返り値を得るのに使われる同期変数、 ii) 関数インスタンスが呼び出されるプロセッサ番号、 iii) 関数名、および iv) その関数の引数 をとります。

二番目の ainvoke の書式は i) プロセッサ番号、 ii) void 型関数の名前、および iii) その関数の引数 をとります。 void 型関数は値を返さないため、同期変数は指定しません。

function-instance-invocation:
ainvoke( sync-var, processor-number, function-name, arguments )
ainvoke( processor-number, function-name, arguments )

次の例では、foo 関数インスタンスが非同期に呼び出されています。foo からの返り値は ss 同期構造に収められます。13 行目では、ss 同期構造に収められた値を読み出し、変数 i に入れています。同期機構 Sync の構文および意味については 4 節 で説明しています。

11 行目では、void 型関数 bar が非同期に呼び出されています。呼び出し側と bar 関数インスタンスが join することはありません。

 1 #include <mpcxx.h> 
 2 int foo(int, int); 
 3 void bar(int, int); 
 4 main(int argc, char **argv;) 
 5 { 
 6 	Sync<int> ss; 
 7 	int i; 
 8 
 9      mpcxx_initialize(argc, argv);
10 	ainvoke(ss, 1, foo, 1, 2); 
11 	ainvoke(2, bar, 10, 20); 
12 
13 	i = *ss; 
14 } 

3.3 制限事項

現在の実装では、呼び出される関数の引数の数は 八つ までに制限されています。


関連項目:

4 同期機構

2 節 で述べられている動機構造は Sync クラステンプレート を用いて実装されています。これは構造が保持しているオブジェクトのデータ型を表す型パラメータを一つとります。

sync-var-definition:
Sync< type-name > variable

図 1 では、整数変数を保持する同期構造 l1 が 13 行目で定義されています。16 行目で、count 関数が l1 を引数としてプロセッサ 1 上で呼び出されています。16 行目は非同期リモート呼び出しであるため、実行はそのまま続けられます。18 行目に示すように、l1 に収められている値は l1 がポインタであるかのようにして取り出されています。実行が 18 行目まで来たとき、l1 がデータを受け取っていれば l1 から値が取り出されます。そうでない場合は、同期構造 l1 が値を受け取るまで実行が一時停止します。

count 関数インスタンスは同期構造 l1 をパラメータ t1 として受け取ります。5 行目および 7 行目で、プロセッサローカルな変数 time がインクリメントされ、その値が l1 に、まるで l1 がポインタであるかのように t1 を介して書き込まれます。

図 1: Sync 使用例
1 #include <mpcxx.h> 
2 int times; 
3 void count(Sync<int> t1) 
4 { 
5 	*t1 = ++times; 
6 	// ... 
7 	*t1 = ++times; 
8 	// ... 
9 }
10 main(int argc, char **argv) 
11 { 
12 	int i; 
13 	Sync<int> l1; 
14 	// ... 
15      mpcxx_initialize(argc, argv);
16 	ainvoke(1, count, l1); 
17 	// ... 
18 	i = *l1; 
19 	// ... 
20 	i = *l1; 
21 }

C++ プログラマは図 1 を見たとき、リモートマシン上の関数 count の t1 で示される同期オブジェクトはリモートマシンにコピーされたオブジェクトであるから、l1 オブジェクトとは異なると思うかもしれません。これはコピーするという意味では正しいですが、同期オブジェクトは一種のグローバルポインタオブジェクトであり、オブジェクトの生成されたプロセッサ番号やそのローカルアドレスを保持しているためうまく動作します。

4.1 その他のオペレーション

同期構造の read/write 操作について解説してきました。これらはポインタの read/write 操作と同じです。ここでは、それ以外の操作、read、write、および queueLength について述べます。

4.1.1 Read オペレーション

Sync オブジェクトには値の収められている変数を得る read メソッド があります。図 1 の 18 行目は以下の行で置き換えることができます。

l1.read(i); // equivalent to i = *l1; 

ポインタの read 操作は余分なコピー操作が含まれるため、変数のサイズが大きい場合には read メソッドを使用したほうが効率的です。

4.1.2 Peek オペレーション

Sync オブジェクトからデータを取り除くことなくデータを読むために peek メソッド が利用できます。オブジェクトからデータが得られない場合、データが得られるようになるまで呼び出し側の実行がブロックされます。peek メソッドは値を受け取る変数を引数にとります。シングル writer/マルチ reader モデル にもとづくプログラムでは peel メソッドが用いられます。次の例では、複数のプロセッサに l1 同期構造を渡して reader 関数インスタンスを呼び出し、その後全ての reader が同じ値を読めるように l1 に値を収めています。

 1 #include <mpcxx.h> 
 2 void reader(Sync<int> t1) 
 3 { 
 4 	int i; 
 5 	t1.peek(i); 
 6 	// ... 
 7 }
 8 main(int argc, char **argv) 
 9 {
10 	Sync<int> l1; 
11
12      mpcxx_initialize(argc, argv);
13 	ainvoke(1, reader, l1); 
14 	ainvoke(2, reader, l1); 
15 	ainvoke(3, reader, l1); 
16 	*l1 = 123; 
17 }

4.1.3 Write オペレーション

Sync オブジェクトには変数の値を受け取ってオブジェクトに書き込む write メソッド があります。図 1 の 5 行目および 7 行目は以下のように置き換えることができます:

t1.write(++times); // equivalent to *t1 = ++times; 

ポインタの write 操作は余分なコピー操作を含むため、データのサイズが大きい場合には write メソッドを使用したほうが効率的です。

4.1.4 Queue Length オペレーション

Sync オブジェクトの queueLength メソッド を用いてオブジェクト内に収められたデータの数を知ることができます。以下に例を示します。

 1 #include <mpcxx.h> 
 2 void worker(Sync<int> done) 
 3 {
 4 	// ... 
 5 	*done = 1; 
 6 }
 7 
 8 main(int argc, char **argv) 
 9 {
10 	Sync<int> done;
11
12      mpcxx_initialize(argc, argv); 
13 	ainvoke(1, worker, done); 
14 	ainvoke(2, worker, done); 
15 	ainvoke(3, worker, done); 
16 	while (done.queueLength() != 3) {
17 		// do something 
18 	}
19 }

5 グローバルポインタ

GlocalPtr クラステンプレート によって実現されるグローバルポインタを用いることで、任意のリモートオブジェクトを参照することができます。GlobalPtr クラステンプレートは、グローバルポインタによって指されるデータの型をパラメータとして取ります。GlobalPtr オブジェクトに対する操作は、グローバルポインタのグローバルポインタが許可されないことを除いて通常のポインタオブジェクトの操作とほとんど同じです。

global-pointer-definition:
GlobalPtr< type-name > variable

簡単な例を以下に示します。foo 関数はグローバルポインタをパラメータとして受け取り、グローバルポインタによって指された領域に値 10 を書き込みます。foo 関数インスタンスは 16 行目で呼び出されています。この行ではローカル変数 g1 がグローバルポインタにキャストして変換されています。

 1 #include <mpcxx.h> 
 2 void foo(GlobalPtr<int> gp) 
 3 { 
 4 	*gp = 10; 
 5 }
 6 void bar(GlobalPtr<int> gp) 
 7 {
 8 	printf(''[Processor %d] *gp = %d\n'', myPE, (int)*gp); 
 9 }
10 main(int argc, char **argv) 
11 {
12 	int g1; 
13 	GlobalPtr<int> gp; 
14
15      mpcxx_initialize(argc, argv);
16 	invoke(1, foo, (GlobalPtr<int>) &g1); 
17 	printf(''[Processor %d] g1 is %d\n'', myPE, g1); 
18 	gp = &g1; 
19 	invoke(2, bar, gp); 
20 }

この例が実行されると、次のようなメッセージが表示されます:

[Processor 0] g1 is 10 
[Processor 1] *gp = 10 

5.1 配列へのグローバルポインタ

以下のプログラムはその他のグローバルポインタの操作について示しています。ほとんどすべてのポインタ操作が示されています。

 1 #include <mpcxx.h> 
 2 void foo(GlobalPtr<int> gp) 
 3 { 
 4 	GlobalPtr<int> t1; 
 5 	gp[0] = myPE; 
 6 	gp[1] = myPE + 1; 
 7 	*(gp + 2) = myPE + 2; 
 8 	t1 = gp + 3; 
 9 	*t1++ = myPE + 3; 
10 	*t1++ = myPE + 4; 
11 }
12 main(int argc, char**argv) 
13 {
14 	int ga[128]; 
15
16      mpcxx_initialize(argc, argv);
17 	invoke(1, foo, (GlobalPtr<int>) ga); 
18 }

5.2 グローバルポインタへのグローバルポインタ

普通のポインタ操作とは違い、グローバルポインタはグローバルポインタを参照することができません。すなわち、下の例の 5 行目は無効な式となります。もしユーザがグローバルポインタへのグローバルポインタを参照したい場合、6 行目および 7 行目に示すように二段階に分けて書く必要があります:

図 2: Mutex クラスと Stack クラス
 1 #include <mpcxx.h> 
 2 class Mutex {
 3 	Sync<int> ss; 
 4 public: 
 5 	Mutex() { *ss = 1; }
 6 	void enter() { int tmp = *ss; }
 7 	void leave() { *ss = 1; }
 8 };
 9 class Stack {
10 	Mutex mm; 
11 	int sp; 
12 	int size; 
13 	int *buf; 
14 	void error() { printf(''out of range %d\n'', sp); }
15 public: 
16 	Stack() { buf = new int[BUF_SIZE]; size = BUF_SIZE; sp = 0; }
17 	Stack(int sz) { buf = new int[sz]; size = sz; sp = 0; }
18 	void push(int v){
19 		mm.enter(); 
20 		if (sp == size) error(); 
21 		else buf[sp++] = v; 
22 		mm.leave(); }
23 	int pop() {
24 		int val; 
25 		mm.enter(); 
26 		if (sp == 0) error(); 
27 		else val = buf[--sp]; 
28 		mm.leave(); 
29 		return val; }
30 };

 1 #include <mpcxx.h> 
 2 void foo(GlobalPtr<GlobalPtr<int> > ggp) 
 3 {
 4 	GlobalPtr<int> gp; 
 5 	// **ggp = myPE; /* error */ 
 6 	gp = *ggp; 
 7 	*gp = myPE; 
 8 }
 9 
10 main(int argc, char**argv) 
11 { 
12 	int i1; 
13 	GlobalPtr<int> gp; 
14 	GlobalPtr<GlobalPtr<int> > ggp; 
15 
16      mpcxx_initialize(argc, argv);
17 	gp = &i1; 
18 	ggp = &gp; 
19 	invoke(1, foo, ggp); 
20 
21 	printf(''i1 = %d\n'', i1); 
22 }

5.3 グローバルオブジェクト呼び出し

プログラマはオブジェクトへのグローバルポインタを用いてオブジェクトの リモートメソッド呼び出し を書くことができます。invoke および ainvoke 関数テンプレートが提供されています。 f

remote-object-method-synchronous-invocation:
invoke( variable, global-pointer, class-name :: member-function-name, arguments )
invoke( global-pinter, class-name :: member-function-name, arguments )
remote-object-method-asynchronous-invocation:
ainvoke( sync-var, global-pointer, class-name :: member-function-name, arguments )
ainvoke( global-pointer, class-name :: member-function-name, arguments )

値を返すメンバ関数用の invoke テンプレートの引数は、 i) 返り値を収める変数名、 ii) グローバルポインタ、 iii) メンバ関数名、および iv) 関数の引数 です。void 型メンバ関数用の invoke テンプレートの引数は、 i) グローバルポインタ、 ii) メンバ関数名、および iii) 関数の引数 です。 invoke 関数はメンバ関数の実行が完了するまで待ちます。

値を返すメンバ関数用の ainvoke テンプレートの引数は、 i) 返り値を収める同期構造変数名。 ii) グローバルポインタ、 iii) メンバ関数名、および iv) 関数の引数 です。ainvoke を使うと、スレッドは関数インスタンスを呼び出し、ブロックされることなくプログラムの続きを実行します。スレッドは同期構造を用いて後で返り値を受け取ります。

void 型メンバ関数用の ainvoke テンプレートの引数は、 i) グローバルポインタ、 ii) メンバ関数名、および iii) 関数の引数 です。void 型関数は値を返さないため、同期変数は指定しません。

以下に例を示します。関数 allocateStack がオブジェクトをリモートプロセッサ内に生成するために定義されています。15 行目でプロセッサ 0 上で動いている main() 関数がプロセッサ 1 上の allocateStack ルーチンを呼び出しています。グローバルポインタ gsp がプロセッサ 1 上に生成されたリモート Stack オブジェクトを指しています。

16 行目で、Stack オブジェクトの void 型メンバ関数 push がグローバルポインタ gsp を用いて同期呼び出しされています。17 行目では、整数値を返す Stack オブジェクトのメンバ関数 pop が同期呼び出しされています。

19 行目および 20 行目が void 型メンバ関数および整数値を返すメンバ関数の非同期呼び出しの霊です。メンバ関数の実行の終了を待たずにプログラムの続きが実行されます。同じプロセッサからのリモートプロセッサへの同期/非同期呼び出しの順序が、リモートプロセッサで処理されるときにも維持されることに再度注意してください。

 1 #include <mpcxx.h> 
 2 GlobalPtr<Stack> 
 3 allocateStack() 
 4 {
 5 	return (GlobalPtr<Stack>) new Stack(); 
 6 }
 7 
 8 main(int argc, char **argv) 
 9 { 
10 	GlobalPtr<Stack> gsp; 
11 	int i; 
12 	Sync<int> si; 
13 
14      mpcxx_initialize(argc, argv);
15 	invoke(gsp, 1, allocateStack); 
16 	invoke(gsp, Stack::push, 1); 
17 	invoke(i, gsp, Stack::pop); 
18 	printf(''i = %d\n'', i); 
19 	ainvoke(gsp, Stack::push, 2); 
20 	ainvoke(si, gsp, Stack::pop); 
21 	i = *si; 
22 	printf(''i = %d\n'', i); 
23 }

ここではリモートオブジェクトを生成する関数をプログラムしました。しかし実際にはユーザはこのような関数をプログラムする必要はありません。7.2 節 で述べるように、関数テンプレート gallocate および gfree がリモートオブジェクトの生成・解放のために用意されています。

5.4 リモートメモリアドレス

2 節 で述べたように、ファイルスコープで定義されている変数は各プロセッサ毎に割り当てられます。すなわち、すべてのプロセッサ上でローカルアドレスが同じになります。 ファイルスコープで定義されているリモートメモリアドレスを変数名を使って指定するのに、GlobalPtr オブジェクトの set メソッド が利用できます。

以下の例では main() ルーチンが各プロセッサ上の変数 dt に 3.1415 をセットするところを示しています:

 1 #include <mpcxx.h> 
 2 double dt; 
 3 main(int argc, char **argv) 
 4 {
 5 	GlobalPtr<double> gdp; 
 6 	int i; 
 7 
 8      mpcxx_initialize(argc, argv);
 9 	for (int i = 0; i < peNum; i++) {
10 		gdp.set(&dt, i); 
11 		*gdp = 3.1415; 
12 	}
13 	// ... 
14 }

5.5 可変長リモートメモリ操作

GlobalPtr オブジェクトには、リモートメモリを読み書きするために nread および nwrite メソッド があります。nread メソッドは i) GlobalPtr オブジェクトによって指されるリモートメモリの内容が収められる ローカルメモリアドレス、 ii) サイズ、および iii) 操作の完了を待つのに用いられる 同期構造 を引数にとります。nwrite メソッドは一番目のパラメータで与えられる データ を GlobalPtr オブジェクトで指されるリモートメモリに書き込みます。二番目のパラメータはメモリの サイズ を指定します。

以下に例を示します:

 1 #include <mpcxx.h> 
 2 double p[256]; 
 3 double q[256]; 
 4 
 5 main(int argc, char **argv) 
 6 {
 7 	GlobalPtr<double> gdp; 
 8 	Sync<int> done; 
 9 	int i; 
10 
11      mpcxx_initialize(argc, argv);
12 	/* q[256] on PE#0 <== p[256] on PE#1 */ 
13 	gdp.set(p, 1); 
14 	gdp.nread(q, 256, done); 
15 	done.read(i); 
16 	/* p[256] on PE#0 ==> q[256] on PE#1 */ 
17 	gdp.set(q, 1); 
18 	gdp.nwrite(p, 256); 
19 }

GlobalPtr オブジェクトの mnwrite メソッドは他のプロセッサにデータを分散するためのマルチキャストリモートメモリ書き込み関数です。以下の例の 14 行目では、プロセッサ 0 上の double の配列 p の値がプロセッサ 1 から peNum - 1 までの double の配列 q にコピーされます。二番目の引数には データサイズ、要素数を指定します。三番目の引数には、各要素がプロセッサ番号を示す 整数配列 を指定し、最後の引数にはその 配列のサイズ を指定します。

1 #include <mpcxx.h> 
2 double q[256]; 
3 double p[256]; 
4 main(int argc, char **argv) 
5 {
6 	GlobalPtr<double> gdp; 
7 	int dest[64]; 
8 
9       mpcxx_initialize(argc, argv);
10 	for (int i = 1; i < peNum; i++) {
11 		dest[i] = i; 
12 	}
13 	gdp.set(q, 0); 
14 	gdp.mnwrite(p, 256, dest, peNum - 1); 
15 }

6 グローバル同期

この節では バリア同期 および リダクション 機能について述べます。

6.1 バリア

Barrier クラスはプロセッサ上のスレッド間のバリア同期機構を実現します。Barrier オブジェクトはファイルスコープオブジェクトでなければなりません。プロセッサ番号 および プロセッサの数 を引数とする setall メソッド で初期化します。プロセッサ数は 2 の累乗でなければなりません。

Barrier オブジェクトの exec メソッド を実行することで、指定されたプロセッサ番号からはじまるプロセッサ上のスレッドが同期されます。このメソッドはバリア同期中に各プロセッサ上のただ一つのスレッドからのみ呼び出されないといけません。以下に例を示します。

 1 #include <mpcxx.h> 
 2 #include <stdio.h> 
 3 #include <Barrier.h> 
 4 Barrier barrier; 
 5 void 
 6 pe_main(Sync<int> done) 
 7 {
 8 	// ... 
 9 	barrier.exec(); 
10 	// ... 
11 	if (myPE == 1) *done = 1; 
12 }
13 main(int argc, char **argv) 
14 {
15 	int i; 
16 	Sync<int> done; 
17
18      mpcxx_initialize(argc, argv);
19 	barrier.setall(1, peNum - 1); 
20 	for (i = 1; i < peNum; i++) {
21 		ainvoke(i, pe_main, done); 
22 	}
23 	done.read(i); 
24 }

6.2 リダクション

クラステンプレート Reduction および ReductionArray はプロセッサ上のスレッド間のリダクション操作を実現します。Reduction は(各プロセッサ上の)変数を一つにまとめるのに使われ、ReductionArray は(各プロセッサ上の)配列の値を一つの配列にまとめるのに使われます。表 1 にあげたリダクション操作をリダクション時に適用できます。

表 1: Reduction および ReductionArray クラステンプレート上のリダクションメソッド

メソッド 意味
sum 値の和
and 値のビット and
xor 値のビット xor
or 値のビット or
max 値の最大値
min 値の最小値

Reduction および ReductionArray オブジェクトはファイルスコープオブジェクトでなければなりません。以下に示すように、値の型をオブジェクトの宣言時に指定します。4 行目で Reduction オブジェクト red1 が整数値をリダクションするために宣言され、5 行目で ReductionArray オブジェクト red2 がサイズが A_SIZE である整数配列をリダクションするために宣言されています。

Reduction および ReductionArray オブジェクトは setall メソッドで初期化する必要があります。setall メソッドはプロセッサ番号とプロセッサの数を引数にとります。プロセッサの数は 2 の累乗でなければなりません。24 行目と 25 行目が例になります。式 peNum - 1 は 2 の累乗でなければなりません。

関数 pe_main() がプロセッサ 1 から peNum - 1 までで呼び出されます。各関数インスタンスは 12 行目でオブジェクト red1 の sum メソッドを呼び、全てのプロセッサ上の myPE の値を足し算して結果を val に入れています。オブジェクト red2 の sum メソッドの呼び出し後は、整数配列 dt は全てのプロセッサ上の dt の値を足し算したものになっています。

 1 #include <mpcxx.h> 
 2 #include <stdio.h> 
 3 #include <Reduction.h> 
 4 Reduction<int> red1; 
 5 ReductionArray<int, A_SIZE> red2; 
 6 int dt[A_SIZE]; 
 7 void 
 8 pe_main(Sync<int> done) 
 9 {
10 	int val; 
11 	// ... 
12 	val = red1.sum(myPE); 
13 	// ... 
14 	red2.sum(dt); 
15 	// ... 
16 	if (myPE == 1) *done = 1; 
17 }
18 main(int argc, char **argv) 
19 {
20 	Sync<int> done; 
21 	int i; 
22 
23      mpcxx_initialize(argc, argv);
24 	red1.setall(1, peNum - 1); 
25 	red2.setall(1, peNum - 1); 
26 	for (i = 1; i < peNum; i++) {
27 		ainvoke(i, pe_main, done); 
28 	}
29 	done.read(i); 
29 }

7 その他の関数

7.1 スレッド実行コントロール

関数 yield() が現在のスレッドの実行を一時停止して他のスレッドに切り替えるために提供されています。他に実行できるスレッドがない場合は、現在のスレッドが走りつづけます。

yield() 関数は他のプロセッサから要求されたリモートスレッド呼び出しやリモートメモリ操作を受け付ける処理を行います。

7.2 リモートオブジェクトの割り当て/解放

テンプレート関数 gallocate および gfree がリモートオブジェクトの割り当ておよび解放に利用できます。gallocate の引数は、リモートオブジェクトのアドレスが収められる グローバルポインタプロセッサ番号、およびコンストラクタの引数 です。gfree は グローバルポインタ を引数としてとります。

5.3 節 のグローバルオブジェクト呼び出しの例ではリモートプロセッサ内に Stack オブジェクトを割り当てるために関数 allocateStack を定義していました。gallocate を使うことで、このような関数を実装する必要がなくなります。以下の例では、2 行目でコンストラクタ Stack() を呼び出してリモート Stack オブジェクトを生成し、そのグローバルポインタを gsp1 に入れています。3 行目ではコンストラクタ Stack(int) を呼び出してリモート Stack オブジェクトを生成し、そのグローバルポインタを gsp2 に入れています。

 1 GlobalPtr<Stack> gsp1, gsp2; 
 2 gallocate(gsp1, 1); // will invoke Stack::Stack() 
 3 gallocate(gsp2, 1, 128);// will invoke Stack::Stack(int) 

参考文献

[1] N. J. Boden, D. Cohen, R. E. Felderman, A. E. Kulawik, C. L. Seitz, J. N. Seizovic, and W. Su. 
Myrinet - A Gigabit-per-Second Local-Area Network. IEEE Micro, Vol. 15, No. 1, pp. 29--36, 
February 1995. 
[2] Yutaka Ishikawa. The MPC++ Programming Language V1.0 Specification with Commentary 
Document Version 0.1. Technical Report TR--94014, RWC, June 1994. 
[3] Yutaka Ishikawa et.al. MPC++. In Gregory V. Wilson and Paul Lu, editors, Parallel 
Programming Using C++, pp. 427--466. MIT Press, 1996. To be published in 1996 Spring. 

A ライブラリ概要

A.1 invoke 関数テンプレート

A.1.1 返り値を持つ関数

以下のテンプレート記述は型 F を返す関数インスタンスの同期呼び出し方法を示しています。

template <class F> 
	int invoke(F &, int pe, F (*f)()); 
template <class F, class A1> 
	int invoke(F &, int pe, F (*f)(A1)); 
template <class F, class A1, class A2> 
	int invoke(F &, int pe, F (*f)(A1, A2)); 
template <class F, class A1, class A2, class A3> 
	int invoke(F &, int pe, F (*f)(A1, A2, A3)); 
template <class F, class A1, class A2, class A3, class A4> 
	int invoke(F &, int pe, F (*f)(A1, A2, A3, A4)); 
template <class F, class A1, class A2, class A3, class A4, class A5> 
	int invoke(F &, int pe, F (*f)(A1, A2, A3, A4, A5)); 
template <class F, class A1, class A2, class A3, class A4, class A5, class A6> 
	int invoke(F &, int pe, F (*f)(A1, A2, A3, A4, A5, A6)); 
template <class F, class A1, class A2, class A3, class A4, class A5, class A6, class A7>
	int invoke(F &, int pe, F (*f)(A1, A2, A3, A4, A5, A6, A7)); 
template <class F, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8> 
	int invoke(F &, int pe, F (*f)(A1, A2, A3, A4, A5, A6, A7, A8)); 

A.1.2 Void 型関数

以下のテンプレート関数によってプログラマは void 型関数インスタンスを同期呼び出しすることができます。

int invoke(int pe, void (*f)()); 
template <class A1> 
	int invoke(int pe, void (*f)(A1)); 
template <class A1, class A2> 
	int invoke(int pe, void (*f)(A1, A2)); 
template <class A1, class A2, class A3> 
	int invoke(int pe, void (*f)(A1, A2, A3)); 
template <class A1, class A2, class A3, class A4> 
	int invoke(int pe, void (*f)(A1, A2, A3, A4)); 
template <class A1, class A2, class A3, class A4, class A5> 
	int invoke(int pe, void (*f)(A1, A2, A3, A4, A5)); 
template <class A1, class A2, class A3, class A4, class A5, class A6> 
	int invoke(int pe, void (*f)(A1, A2, A3, A4, A5, A6)); 
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7> 
	int invoke(int pe, void (*f)(A1, A2, A3, A4, A5, A6, A7)); 
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8> 
	int invoke(int pe, void (*f)(A1, A2, A3, A4, A5, A6, A7, A8)); 

A.1.3 返り値を持つグローバルオブジェクトメンバ関数

以下のテンプレート記述は、型 F の値を返すメンバ関数インスタンスをグローバルポインタ GlobalPtr<T> を介して同期呼び出しする方法を示しています。

template <class T, class F> 
	int invoke(F &, GlobalPtr<T>, F (T::*f)()); 
template <class T, class F, class A1> 
	int invoke(F &, GlobalPtr<T>, F (T::*f)(A1)); 
template <class T, class F, class A1, class A2> 
	int invoke(F &, GlobalPtr<T>, F (T::*f)(A1, A2)); 
template <class T, class F, class A1, class A2, class A3> 
	int invoke(F &, GlobalPtr<T>, F (T::*f)(A1, A2, A3)); 
template <class T, class F, class A1, class A2, class A3, class A4> 
	int invoke(F &, GlobalPtr<T>, F (T::*f)(A1, A2, A3, A4)); 
template <class T, class F, class A1, class A2, class A3, class A4, class A5> 
	int invoke(F &, GlobalPtr<T>, F (T::*f)(A1, A2, A3, A4, A5)); 
template <class T, class F, class A1, class A2, class A3, class A4, class A5, class A6> 
	int invoke(F &, GlobalPtr<T>, F (T::*f)(A1, A2, A3, A4, A5, A6)); 
template <class T, class F, class A1, class A2, class A3, class A4, class A5, class A6, class A7> 
	int invoke(F &, GlobalPtr<T>, F (T::*f)(A1, A2, A3, A4, A5, A6, A7)); 
template <class T, class F, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8> 
	int invoke(F &, GlobalPtr<T>, F (T::*f)(A1, A2, A3, A4, A5, A6, A7, A8));

A.1.4 グローバルオブジェクト Void 型メンバ関数

以下のテンプレート関数によってプログラマは void 型メンバ関数インスタンスをグローバルポインタ GlobalPtr<T> を介して同期呼び出しすることができます。

template <class T> 
	int invoke(GlobalPtr<T>, void (T::*f)()); 
template <class T, class A1> 
	int invoke(GlobalPtr<T>, void (T::*f)(A1)); 
template <class T, class A1, class A2> 
	int invoke(GlobalPtr<T>, void (T::*f)(A1, A2)); 
template <class T, class A1, class A2, class A3> 
	int invoke(GlobalPtr<T>, void (T::*f)(A1, A2, A3)); 
template <class T, class A1, class A2, class A3, class A4> 
	int invoke(GlobalPtr<T>, void (T::*f)(A1, A2, A3, A4)); 
template <class T, class A1, class A2, class A3, class A4, class A5> 
	int invoke(GlobalPtr<T>, void (T::*f)(A1, A2, A3, A4, A5)); 
template <class T, class A1, class A2, class A3, class A4, class A5, class A6> 
	int invoke(GlobalPtr<T>, void (T::*f)(A1, A2, A3, A4, A5, A6)); 
template <class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7>
	int invoke(GlobalPtr<T>, void (T::*f)(A1, A2, A3, A4, A5, A6, A7)); 
template <class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8> 
	int invoke(GlobalPtr<T>, void (T::*f)(A1, A2, A3, A4, A5, A6, A7, A8)); 

A.2 ainvoke 関数テンプレート

A.2.1 返り値を持つ関数

以下のテンプレート記述は型 F の値を返す関数インスタンスを非同期に呼び出す方法を示しています。

template <class F> 
	int ainvoke(Sync<F> &, int pe, F (*f)()); 
template <class F, class A1> 
	int invoke(Sync<F> &, int pe, F (*f)(A1)); 
template <class F, class A1, class A2> 
	int invoke(Sync<F> &, int pe, F (*f)(A1, A2)); 
template <class F, class A1, class A2, class A3> 
	int invoke(Sync<F> &, int pe, F (*f)(A1, A2, A3)); 
template <class F, class A1, class A2, class A3, class A4> 
	int invoke(Sync<F> &, int pe, F (*f)(A1, A2, A3, A4)); 
template <class F, class A1, class A2, class A3, class A4, class A5> 
	int invoke(Sync<F> &, int pe, F (*f)(A1, A2, A3, A4, A5)); 
template <class F, class A1, class A2, class A3, class A4, class A5, class A6> 
	int invoke(Sync<F> &, int pe, F (*f)(A1, A2, A3, A4, A5, A6)); 
template <class F, class A1, class A2, class A3, class A4, class A5, class A6, class A7>
	int invoke(Sync<F> &, int pe, F (*f)(A1, A2, A3, A4, A5, A6, A7)); 
template <class F, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8> 
	int invoke(Sync<F> &, int pe, F (*f)(A1, A2, A3, A4, A5, A6, A7, A8)); 

非同期に呼び出された関数インスタンスからの返り値が必要ない場合、以下の関数テンプレートを用いるべきです。すなわち、Sync オブジェクトを指定する代わりに NullSync オブジェクトが指定されます。

template <class F> 
	int ainvoke(NullSync, int pe, F (*f)()); 
template <class F, class A1> 
	int invoke(NullSync, int pe, F (*f)(A1)); 
template <class F, class A1, class A2> 
	int invoke(NullSync, int pe, F (*f)(A1, A2)); 
template <class F, class A1, class A2, class A3> 
	int invoke(NullSync, int pe, F (*f)(A1, A2, A3)); 
template <class F, class A1, class A2, class A3, class A4> 
	int invoke(NullSync, int pe, F (*f)(A1, A2, A3, A4)); 
template <class F, class A1, class A2, class A3, class A4, class A5> 
	int invoke(NullSync, int pe, F (*f)(A1, A2, A3, A4, A5)); 
template <class F, class A1, class A2, class A3, class A4, class A5, class A6> 
	int invoke(NullSync, int pe, F (*f)(A1, A2, A3, A4, A5, A6)); 
template <class F, class A1, class A2, class A3, class A4, class A5, class A6, class A7>
	int invoke(NullSync, int pe, F (*f)(A1, A2, A3, A4, A5, A6, A7)); 
template <class F, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8> 
	int invoke(NullSync, int pe, F (*f)(A1, A2, A3, A4, A5, A6, A7, A8));

A.2.2 Void 型関数

以下の関数テンプレートによってプログラマは void 型関数を非同期に呼び出すことができます。

int ainvoke(int pe, void (*f)()); 
template <class A1> 
	int ainvoke(int pe, void (*f)(A1)); 
template <class A1, class A2> 
	int ainvoke(int pe, void (*f)(A1, A2)); 
template <class A1, class A2, class A3> 
	int ainvoke(int pe, void (*f)(A1, A2, A3)); 
template <class A1, class A2, class A3, class A4> 
	int ainvoke(int pe, void (*f)(A1, A2, A3, A4)); 
template <class A1, class A2, class A3, class A4, class A5> 
	int ainvoke(int pe, void (*f)(A1, A2, A3, A4, A5)); 
template <class A1, class A2, class A3, class A4, class A5, class A6> 
	int ainvoke(int pe, void (*f)(A1, A2, A3, A4, A5, A6)); 
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7> 
	int ainvoke(int pe, void (*f)(A1, A2, A3, A4, A5, A6, A7)); 
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8> 
	int ainvoke(int pe, void (*f)(A1, A2, A3, A4, A5, A6, A7, A8)); 

A.2.3 返り値を持つグローバルオブジェクトメンバ関数

以下のテンプレート記述は、型 F の値を返すメンバ関数インスタンスをグローバルポインタ GlobalPtr<T> を介して非同期呼び出しする方法を示しています。

template <class T, class F> 
	int ainvoke(Sync<F> &, GlobalPtr<T>, F (T::*f)()); 
template <class T, class F, class A1> 
	int ainvoke(Sync<F> &, GlobalPtr<T>, F (T::*f)(A1)); 
template <class T, class F, class A1, class A2> 
	int ainvoke(Sync<F> &, GlobalPtr<T>, F (T::*f)(A1, A2)); 
template <class T, class F, class A1, class A2, class A3> 
	int ainvoke(Sync<F> &, GlobalPtr<T>, F (T::*f)(A1, A2, A3)); 
template <class T, class F, class A1, class A2, class A3, class A4> 
	int ainvoke(Sync<F> &, GlobalPtr<T>, F (T::*f)(A1, A2, A3, A4)); 
template <class T, class F, class A1, class A2, class A3, class A4, class A5> 
	int ainvoke(Sync<F> &, GlobalPtr<T>, F (T::*f)(A1, A2, A3, A4, A5)); 
template <class T, class F, class A1, class A2, class A3, class A4, class A5, class A6> 
	int ainvoke(Sync<F> &, GlobalPtr<T>, F (T::*f)(A1, A2, A3, A4, A5, A6)); 
template <class T, class F, class A1, class A2, class A3, class A4, class A5, class A6, class A7> 
	int ainvoke(Sync<F> &, GlobalPtr<T>, F (T::*f)(A1, A2, A3, A4, A5, A6, A7)); 
template <class T, class F, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8> 
	int invoke(Sync<F> &, GlobalPtr<T>, F (T::*f)(A1, A2, A3, A4, A5, A6, A7, A8)); 

非同期に呼び出されたメンバ関数インスタンスからの返り値が必要ない場合、以下の関数テンプレートを用いるべきです。すなわち、Sync オブジェクトを指定する代わりに NullSync オブジェクトが指定されます。

template <class T, class F> 
	int ainvoke(NullSync, GlobalPtr<T>, F (T::*f)()); 
template <class T, class F, class A1> 
	int ainvoke(NullSync, GlobalPtr<T>, F (T::*f)(A1)); 
template <class T, class F, class A1, class A2> 
	int ainvoke(NullSync, GlobalPtr<T>, F (T::*f)(A1, A2)); 
template <class T, class F, class A1, class A2, class A3> 
	int ainvoke(NullSync, GlobalPtr<T>, F (T::*f)(A1, A2, A3)); 
template <class T, class F, class A1, class A2, class A3, class A4> 
	int ainvoke(NullSync, GlobalPtr<T>, F (T::*f)(A1, A2, A3, A4)); 
template <class T, class F, class A1, class A2, class A3, class A4, class A5> 
	int ainvoke(NullSync, GlobalPtr<T>, F (T::*f)(A1, A2, A3, A4, A5)); 
template <class T, class F, class A1, class A2, class A3, class A4, class A5, class A6> 
	int ainvoke(NullSync, GlobalPtr<T>, F (T::*f)(A1, A2, A3, A4, A5, A6)); 
template <class T, class F, class A1, class A2, class A3, class A4, class A5, class A6, class A7> 
	int ainvoke(NullSync, GlobalPtr<T>, F (T::*f)(A1, A2, A3, A4, A5, A6, A7)); 
template <class T, class F, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8> 
	int ainvoke(NullSync, GlobalPtr<T>, F (T::*f)(A1, A2, A3, A4, A5, A6, A7, A8)); 

A.2.4 グローバルオブジェクト Void 型メンバ関数

以下のテンプレートによってプログラマは void 型メンバ関数インスタンスをグローバルポインタ GlobalPtr<T> を介して非同期呼び出しすることができます。

template <class T> 
	int ainvoke(GlobalPtr<T>, void (T::*f)()); 
template <class T, class A1> 
	int ainvoke(GlobalPtr<T>, void (T::*f)(A1)); 
template <class T, class A1, class A2> 
	int ainvoke(GlobalPtr<T>, void (T::*f)(A1, A2)); 
template <class T, class A1, class A2, class A3> 
	int ainvoke(GlobalPtr<T>, void (T::*f)(A1, A2, A3)); 
template <class T, class A1, class A2, class A3, class A4> 
	int ainvoke(GlobalPtr<T>, void (T::*f)(A1, A2, A3, A4)); 
template <class T, class A1, class A2, class A3, class A4, class A5> 
	int ainvoke(GlobalPtr<T>, void (T::*f)(A1, A2, A3, A4, A5)); 
template <class T, class A1, class A2, class A3, class A4, class A5, class A6> 
	int ainvoke(GlobalPtr<T>, void (T::*f)(A1, A2, A3, A4, A5, A6)); 
template <class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7>
	int ainvoke(GlobalPtr<T>, void (T::*f)(A1, A2, A3, A4, A5, A6, A7)); 
template <class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8> 
	int ainvoke(GlobalPtr<T>, void (T::*f)(A1, A2, A3, A4, A5, A6, A7, A8)); 

A.3 Sync クラステンプレート

Sync オブジェクトへの read/write 操作に加えて、以下のメソッドが利用できます:

template<class T> class Sync {
public: 
	operator T(); /* casting */ 
	void read(T&); 
	void peek(T&); 
	void write(T&); 
	int queueLength(); 
}
read(T&)
データが Sync オブジェクトから取り出され、引数に指定された変数に収められます。
peek(T&)
データが Sync オブジェクトから読み出され、引数に指定された変数に収められます。操作後もデータは Sync オブジェクト内に残ったままです。
write(T&)
引数に指定された値が Sync オブジェクトのキューに入れられます
queueLength()
取り出し可能な値の数が返されます

A.4 GlobalPtr クラステンプレート

ポインタの read/write および GlobalPtr オブジェクトの increment/decrement 操作に加えて、以下のメソッドが利用できます:

template<class T> class GlobalPtr {
public: 
	void set(void *laddr, int pe); 
	void set(void *laddr); 
	int getPe(); 
	void *getLaddr(); 
	void nwrite(T *laddr, int nitem); 
	void nread(T *laddr, int nitem, Sync<int> sync); 
	void mnwrite(T *laddr, int nitem, int dest[], int dsize); 
}
void set(void *laddr, int pe)
メソッドの実行後、GlobalPtr オブジェクトはプロセッサ pe 上の laddr が示すメモリアドレスにあるオブジェクトを指します。
void set(void *laddr)
GlobalPtr オブジェクトのローカルメモリアドレスを変更します。
int getPe()
GlobalPtr オブジェクトによって指されるオブジェクトのプロセッサ番号を返します。
void *getLaddr()
GlobalPtr オブジェクトによって指されるオブジェクトのローカルアドレスを返します。
void nwrite(T *laddr, int nitem)
GlobalPtr オブジェクトによって表されるリモートメモリに laddr が指すデータを書き込みます。データサイズ、要素数が二番目の引数で指定されます。
void nread(T *laddr, int nitem, Sync<int> sync)
GlobalPtr オブジェクトによって表されるデータを読み込み、laddr が指すメモリにデータを収めます。データサイズ、要素数が二番目の引数で指定されます。
void mnwrite(T *laddr, int nitem, int dest[], int dsize)
プロセッサ番号の配列 dest で指定された全てのプロセッサ上の、ローカルアドレスが GlobalPtr オブジェクトによって表されるリモートメモリに laddr が指すデータを書き込みます。データサイズ、要素の数は二番目の引数 nitem で指定します。三番目の引数 dest の配列サイズは最後の引数 dsize で指定します。

A.5 Barrier および Reduction クラス

A.6 その他

yield() 関数は現在のスレッドの実行を一時停止し、他のスレッドに実行を移します。

void yield(); 

gallocate 関数テンプレートは二番目の引数で指定されたプロセッサ上でオブジェクトを生成します。オブジェクトのクラスは最初の引数、クラスを指定している GlobalPtr オブジェクトによって解決されます。

template<class T> 
	GlobalPtr<T> gallocate(GlobalPtr<T>&, int pe); 
template<class T, class A1> 
	GlobalPtr<T> gallocate(GlobalPtr<T>&, int pe, A1); 
template<class T, class A1, class A2> 
	GlobalPtr<T> gallocate(GlobalPtr<T>&, int pe, A1, A2); 
template<class T, class A1, class A2, class A3> 
	GlobalPtr<T> gallocate(GlobalPtr<T>&, int pe, A1, A2, A3); 
template<class T, class A1, class A2, class A3, class A4> 
	GlobalPtr<T> gallocate(GlobalPtr<T>&, int pe, A1, A2, A3, A4); 
template<class T, class A1, class A2, class A3, class A4, class A5> 
	GlobalPtr<T> gallocate(GlobalPtr<T>&, int pe, A1, A2, A3, A4, A5); 
template<class T, class A1, class A2, class A3, class A4, class A5, class A6> 
	GlobalPtr<T> gallocate(GlobalPtr<T>&, int pe, A1, A2, A3, A4, A5, A6); 
template<class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7> 
	GlobalPtr<T> gallocate(GlobalPtr<T>&, int pe, A1, A2, A3, A4, A5, A6, A7); 
template<class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8> 
	GlobalPtr<T> gallocate(GlobalPtr<T>&, int pe, A1, A2, A3, A4, A5, A6, A7, A8); 

gfree 関数テンプレートは GlobalPtr オブジェクトが指すオブジェクトを解放します:

template<class T> 
	void gfree(GlobalPtr<T> &); 


PC Cluster Consortium

CREDIT
This document is a part of the SCore cluster system software developed at PC Cluster Consortium, Japan. Copyright (C) 2003 PC Cluster Consortium.