x10でのGlobalRef,PlaceLocalHandleの使い方

# はじめに

x10はAPGASモデルを採用しており、変数は各Place上で確保されています。
基本的にはローカル変数などを作ったらそのPlace上にのみメモリが確保されて、atでplaceを移動するときに参照している変数が移動先のplaceにコピーされます。

すべてのPlaceで共通に参照する変数を作りたい場合、`GlobalRef`, `PlaceLocalHandle` というクラスを使います。
例えば、各placeで計算した結果の和を集めたい場合に `GlobalRef` を使います。
変数の実体はあるPlaceのみに存在しますが、GlobalRefでその変数への参照をPlace間で共有することができます。

ここではGlobalRefと、その分散バージョンであるPlaceLocalHandleの初歩的な使い方を解説します。

参考情報

- http://x10.sourceforge.net/x10doc/latest/
    - x10.LangパッケージのGlobalRef および PlaceLocalHandle
- http://x10.sourceforge.net/tutorials/x10-2.4/APGASProgrammingInX10/APGASprogrammingInX10-slides-V7.pdf
    - 43枚目あたり

# GlobalRefの使い方

基本的なサンプルコードは以下のとおり。

各placeでn(0)に１ずつ足しています。

```x10
class HelloGlobalRef {
  public static def main(args:Rail[String]):void {

    var n:Cell[Long] = new Cell[Long](0);
    // var Long にするとerror。GlobalRefの引数にはreferenceしか入れられないので、CellかRailにする。
    val ref = new GlobalRef[Cell[Long]](n);

    for( p in Place.places() ) at(p) {
      at(ref) ref()() += 1;
    }

    Console.OUT.println(n);
    Console.OUT.println( "Num places: " + Place.numPlaces() );
  }
}
```

実行結果（環境変数X10_NPLACESでplace数を指定している）

```
$ X10_NPLACES=4 ./a.out
[4]
Num places: 4
```

GlobalRefの参照先の変数を取得・変更したい場合には、明示的にその変数が定義されているplaceに`at`で移動する必要があります。`at(ref) ref() ....` という部分。
プログラマにatを明示的に書かせることを強制するのはx10のデザインで、明示的に書くことによってコピーが起こっていることが分かりやすくなります。
ちなみに `at(ref)` というのは `at(ref.home)` のsyntax sugarです。`ref.home`は実体が存在するplaceを返すプロパティです。

もし `at(ref)` を書き忘れた場合、コンパイル時に以下のような警告が出て

```
x10c++: 1 dynamically checked calls or field accesses, run with -VERBOSE_CHECKS for more details.
```

以下のように実行時エラーが起きます。
このようなエラーが起きた時には、atの書き忘れの可能性が高いです。

```
Uncaught exception at place 0: x10.lang.MultipleExceptions
x10.lang.FailedDynamicCheckException: !(here == t$85.home)
	at x10aux::throwException(x10::lang::CheckedThrowable*)
        ...
```

非同期のコードの実行サンプルは以下の通りです。
GlobalRefを更新する場合は `atomic` をつける必要があります。atomicが無いと結果の正しさが保証されません。

```x10
finish for( p in Place.places() ) at(p) async {
  at(ref) atomic ref()() += 1;
}
```

ちなみに上のコードのrefに対する一つ目の`()`はGlobalRefの参照外しを行っていて、二つ目の`()`はCellの中身を取り出しています。

# PlaceLocalHandleの使い方

GlobalRefと似ているが、複数のオブジェクトを複数のPlaceで分散して保持したい場合に使えます。例えば、巨大な配列を複数のPlaceで分割して保持する用途に使えます。

サンプルコードを見てみましょう。

```x10
class HelloPlaceLocalHandle {
  public static def main(args:Rail[String]):void {

    val plh = PlaceLocalHandle.make[Cell[Long]]( Place.places(), () => new Cell[Long](0) );
    // 各Placeで、第二引数のlambdaを実行し、作成されたオブジェクトへの参照をplhとして持つ。

    for( p in Place.places() ) at(p) {
      plh()(p.id);   // 各placeのcellにplaceのidを代入
    }

    for( p in Place.places() ) at(p) {
      Console.OUT.println( "Current place: " + p.id );
      Console.OUT.println( "  Value of PLH: " + plh() );
    }
  }
}
```

`PlaceLocalHandle.make` の第二引数のlambdaが各place上で実行され、`Cell[Long](0)`が各placeでつくられます。
`plh()`で自分のplaceの参照先オブジェクトを取得することができます。

実行結果は以下の通りです。

```txt
$ X10_NPLACES=4 ./a.out
Current place: 0
  Value of PLH: Cell(0)
Current place: 1
  Value of PLH: Cell(1)
Current place: 2
  Value of PLH: Cell(2)
Current place: 3
  Value of PLH: Cell(3)
```

より実用的な例は[チュートリアルスライド](http://x10.sourceforge.net/tutorials/x10-2.4/APGASProgrammingInX10/APGASprogrammingInX10-slides-V7.pdf)の50枚目を参照してください。