Joyceは、1980年代にPer Brinch Hansenによって設計された、並行コンピューティングのための安全なプログラミング言語です。 [ 1 ]これは、逐次言語Pascalと通信逐次プロセス(CSP)の原理に基づいています。プログラミング言語として適用する際のCSPの欠点を克服し、主に教育目的で分散コンピューティングシステムの実装のためのツールを提供するために作成されました。
この言語はエージェントという概念に基づいています。エージェントとは、チャネルとメッセージパッシングのみを使用して通信する、並行して実行されるプロセスのことです。エージェントは、サブエージェントを動的かつ再帰的に起動できます。Joyceの開発は、同じくHansenが1993年頃に開発したSuperPascal言語の基礎となりました。
JoyceはPascalの小さなサブセットをベースにしており、並行処理のためにCSPから着想を得た機能が追加されています。[ 2 ]次のセクションでは、導入されたより斬新な機能のいくつかについて説明します。
エージェントとは、一連のステートメントと、場合によってはネストされた他のエージェントの定義から構成される手続きです。エージェントは、作成者と同時に実行されるサブエージェントを動的にアクティブ化できます。エージェントは、すべてのサブエージェントが終了した場合にのみ終了できます。たとえば、エージェントは以下をアクティブ化します。process2process1
エージェントプロセス1 (x 、y :整数)始める...終わり;エージェントプロセス2 () ;プロセス1を使用する。始めるプロセス1 (9、17 )終わり;エージェントが起動すると、すべてのローカル変数の新しいインスタンスが作成され、各仮パラメータの値がローカル変数にコピーされます。そのため、エージェントは他のエージェントの変数にアクセスできず、チャネルを介してのみ通信できます。この制限により、競合状態など、共有変数の使用に伴う問題を防ぐことができます。
エージェントはチャネルと呼ばれるエンティティを介して通信します。チャネルには、送信可能なシンボルのセットを定義するアルファベットがあります。チャネルは動的に作成され、ポート変数を使用してアクセスされます。ポートタイプは、そのアルファベットを構成する固有のシンボルセットによって定義されます。複数の値を持つシンボルは、特定のタイプで定義されます。例:
stream = [ int ( integer ) , eos ] ;このシンボルは、任意の整数値を持つメッセージシンボルint(integer)を表します。2 番目の型なしシンボル宣言(ストリームの終了) はシグナルと呼ばれます。ポート型が定義されると、その型のポート変数を宣言できます。inteos
出力: ストリーム ストリーム内 そして、エージェント内部のチャネルエンティティは、次のようにしてアクティブ化できます。
+出力; ?その後、シンボルはCSPスタイルの入力演算子と出力演算子を使用してチャネル上で送受信できます!。通信は、送信エージェントと一致する受信エージェントが存在する場合にのみ発生します。受信エージェントは、送信されるシンボルタイプを受信することを想定する必要があります。たとえば、値9に続いてeosシンボルがポートに送信されますout。
出力! int ( 9 )出力! eosそして、整数メッセージが一致する型の変数に受信され、その後にコロンが続きますeos。
受信した値:整数(受信)はeosですか?ポーリングステートメントは、CSPのガード付き代替案の概念に基づいています。ポーリングステートメントは一連のステートメントで構成され、各ステートメントは入力チャネルステートメントによってガードされます。送信エージェントとガードの間で通信が一致すると、ガードが実行され、続いて対応するステートメントが実行されます。例:
投票 ? X -> x := x + 1 | ? Y -> y := y + 1 終わり ポートがin信号Xまたはを監視している場合Y、一致する通信が発生すると、対応する変数xまたはがyインクリメントされます。
Joyceは、コンパイラが言語規則へのすべての違反を検出できるという意味で、安全な言語として設計された。
以下は、Joyceプログラミング言語を紹介する元の論文[ 1 ]から抜粋した完全なサンプルプログラムで、素数生成のための篩分け技術に基づいて素数を生成するアルゴリズムを実装しています。sieveエージェントは、先行エージェントから整数のストリームを受け取ります。最初の整数は素数です。エージェントは、ストリームからこの素数の倍数をすべて削除し、後継エージェントをアクティブ化します。これは、eos信号が篩のセットに沿って伝播されるまで続きます。
agent sieve ( inp , out : stream ) ; var more : boolean ; x , y : integer ; succ : stream ; begin poll inp ? int ( x ) -> + succ ; sieve ( succ , out ) ; more := true | inp ? eos -> out ! eos ; more := false end ; while more do poll inp ? int ( y ) -> if y mod x <> 0 then succ ! int ( y ) | inp ? eos -> out ! int ( x ) ; succ ! eos ; more := false end ; end ;以下のエージェントは、ふるい分けエージェントのセットを初期化し、3から9999までの整数のストリームをそれらに入力します。
エージェント素数;生成、篩分け、印刷を使用;変数a 、b :ストリーム;開始+ a ; + b ;生成( a 、3、2、4999 ) ;篩分け( a 、b ) ;印刷( b )終了;エージェントプロシージャの同時実行のため、エージェント呼び出しのアクティベーションレコードが後入れ先出しパターンに従わないため、従来の逐次スタック割り当て方式は使用できません。代わりに、クリエーターとサブエージェントの関係はツリー構造のスタックを形成します。この動作を実装するために、スタックの最上位に新しいアクティベーションレコードを割り当て、サブエージェントのアクティベーションレコードをクリエーターのレコードにリンクするというシンプルな方式が用いられます。これらのレコードは、エージェントが終了し、スタックの最上位にある場合にのみ解放されます。 [ 3 ]この方式の有効性は、プログラムの構造と動作に依存し、場合によってはメモリ使用効率が低下することがあります。より効率的な方式は、Hansen の言語SuperPascalで実装されました。