ThreadQueue
5.1 並行オブジェクト
第
5章
MILK
のアーキテクチャ
MILKのソースコードは、トランスレータでJavaソースコードに変換して、それをJava コンパイラでコンパイルすることで実行することができる。トランスレータは、まずソー スコードをスキャナでトークンの列に切り分ける。切り分けられたトークンの列はパーサ に渡され、構文木が作成される。木の各ノードはオブジェクトで構成され、各構文の必要 な情報を保持している。そして、トランスレータはこの構文木をたどり、Javaから拡張し た構文を発見するとJavaで動作するコードに変換しながら、再び文字列に戻していく。最 後に、できた文字列をファイルに出力する。計算機言語の仕組みについては文献[23]が参 考になる。
トランスレータはJDKversion1.0.2によって実装されている。JDKはSunMicrosystems
がフリーで公開しているJavaの開発キットである。トランスレータのパーサ部分はCUP
version 0.9e [24] によって実装されている。 CUP は YACC に良く似た Java のための
LALR パーサのジェネレータである。
この章では MILK がどのようにして Java に変換され、Java レベルではどのように実 装されているのかを説明する。
public void sayHello(String name) {
System.out.println("Hello " + name);
}
}
図5.1: 並行オブジェクトのクラス定義
5.1.1 ConcurrentObject
図 5.1 では親クラスを指定していない。並行オブジェクトクラスでは親クラスが指定さ れていない時には milk.runtime.ConcurrentObject が指定された事になる。また、親クラ スを指定する時には必ず ConcurrentObject を継承しているものを指定しなくてはならな い。ConcurrentObject の実装は図5.4 のようになっている。ConcurrentObject はインス タンス変数として、キューとスレッドを持っている。メソッド run() は並行オブジェクト のスレッドが最初に実行するメソッドである。このメソッドはこのクラスを継承したクラ スで実装しなくてはならない。
メソッド $MILK$activate()はスレッド生成のためのメソッドである。 メソッド
$MILK$checkQueue()はキューを調べ、キューが空の時にスレッドを破棄するためのメソッ
ドである。この2つのメソッドは同時に実行される事があってはならないのでsynchronized
宣言してある。Javaでは、同じオブジェクトのsynchronized 宣言したメソッドは同時に 実行されることはない。スレッドの扱い方には、必要な時に生成して必要が無くなった時 に破棄する方法を採用した。この他に1回だけスレッドを生成してそのスレッドを必要に 応じてサスペンドさせたりレジュームさせたりする方法が考えられる。この方法はサスペ ンドとレジュームのコストが破棄と生成のコストよりも安いように思えるが、実際はほと んど差が無い。また、サスペンドしたスレッドがあると Javaプログラムは終了しないの で、プログラムの終了条件についても考えなくてはならない。従って、前者の方法を採用 した。メソッド$MILK$checkQueue() の変数 tmp はカレントスレッドが $MILK$thread
と等しい時でも正しく動作させるために必要である。
$MILK$select() については後で説明する。$MILK$error() は並行オブジェクトで発生 したエラーを通告するためのメソッドである。
private void $MILK$sayHello(String name) {
System.out.println("Hello " + name);
}
public synchronized void sayHello(String name) {
$MILK$queue.put("A");
$MILK$queue.put(new Integer(0));
$MILK$queue.put(name);
$MILK$activate();
}
protected void $MILK$select(String name, int num) {
if (name.equals("A")) {
switch (num) {
case 0:
$MILK$sayHello((String)$MILK$queue.get());
break;
default:
$MILK$error(name, num);
break;
}
}
else {
super.$MILK$select(name, num);
}
}
図5.2: Java に変換された並行オブジェクトのクラス定義
if ($MILK$thread != Thread.currentThread()) {
return;
}
while (true) {
$MILK$checkQueue();
$MILK$select((String)$MILK$queue.get(),
((Integer)$MILK$queue.get()).intValue());
}
}
}
図5.2: Javaに変換された並行オブジェクトのクラス定義(つづき)