Concurrent Pascalは、共有メモリコンピュータ上でオペレーティングシステムやリアルタイムコンピューティング監視システムなどの並行コンピューティングプログラムを記述するためにPer Brinch Hansenによって設計されたプログラミング言語です。[ 1 ]
別の言語であるシーケンシャルパスカルは、コンカレントパスカルで書かれたオペレーティングシステムによって実行されるアプリケーションプログラムの言語として使用されます。どちらの言語もニクラウス・ヴィルトのパスカルの拡張であり、共通のスレッドコードインタープリタを共有しています。[ 2 ]以下では、コンカレントパスカルがヴィルトのパスカルとどのように異なるかを説明します。
シンプルさとセキュリティのために、Pascal のいくつかの構成要素が Concurrent Pascal から削除されました: [ 2 ]
これらの省略により、コンパイル時のチェックとスレッドコードインタープリタにおける最小限の実行時チェックを組み合わせることで、プログラムが割り当てられた領域外にアクセスすることによって、プログラム自身や他のプログラムに損害を与えることがないことを保証することが可能になります。
Concurrent Pascalには、クラス、モニター、プロセスといったデータ型が含まれています。これらの型のインスタンスは変数として宣言され、initステートメント内で初期化されます。
クラスとモニタは似ています。どちらもプライベート変数とプロシージャをパブリックプロシージャ(プロシージャエントリと呼ばれる)でパッケージ化します。クラスインスタンスは1つのプロセスでのみ使用できますが、モニタインスタンスは複数のプロセスで共有できます。コンカレントPascalプログラムにおいて、プロセス間通信を実現する唯一のメカニズムはモニタです。
特定のモニタインスタンス内では、一度に実行できるプロセスは 1 つだけです。組み込みデータ型であるキューは、操作 および とともにdelay、continueモニタ内でのスケジューリングに使用されます。キュー型の変数はそれぞれ 1 つのプロセスを保持できます。モニタ内で複数のプロセスを遅延させる場合は、通常配列として構成される複数のキュー変数を用意する必要があります。単一のプロセスキュー変数により、モニタは中期的なスケジューリングを完全に制御できますが、適切なプロセスをブロック解除するのはプログラマの責任です。
クラスやモニタのようなプロセスは、ローカル変数、プロシージャ、および初期ステートメントを持ちますが、プロシージャエントリはありません。初期ステートメントは通常、ローカルプロシージャ、クラスプロシージャ、およびモニタプロシージャを呼び出しながら永久に実行されます。プロセスはモニタプロシージャを介して通信します。言語規則は、モニタに階層構造を課すことでデッドロックを防ぎます。しかし、モニタが遅延したプロセスのブロック解除を誤って忘れる(continueを呼び出さない)ことを防ぐことはできません。そのため、プログラミングエラーによってシステムが事実上ハングアップする可能性があります。
Concurrent Pascal プログラムにおけるプロセス、モニタ、およびクラスの構成は、通常、実行開始時に確立され、その後は変更されません。initクラスおよびモニタのインスタンス変数はプロシージャのパラメータとして使用できないため、これらのコンポーネント間の通信経路は、ステートメントで渡される変数によって確立されます。
以下の例は、シンプルなモニタの宣言と、通信を行う2つのプロセスによるそのモニタの使用方法を示しています。
タイプ 「境界バッファモニタ」 バッファ = モニター 変数 saved : Integer; "保存されたアイテムは整数です" fullq, emptyq : Queue; "2つのプロセスのみで使用されます" full : Boolean; "アイテムが保存されている場合はtrue:"「アイテムをバッファに格納します」procedureentryput(item:Integer);始めるiffullthendelay(fullq); "満杯の場合はブロック" saved := item; "アイテムを保存" full := true; "満杯としてマーク" continue(emptyq) "コンシューマーのブロックを解除" 終わり; 「バッファからアイテムを取得します」procedureentryget(varitem:Integer);始めるifnotfullthendelay(emptyq); "空の場合はブロック" item := saved; "アイテムを取得" full := false; "満杯ではないとマーク" continue(fullq) "プロデューサーのブロックを解除" 終わり; 「モニターを初期化します」 始める full := false 終わり; 「プロデューサーはバッファを使用します」 プロデューサー = process(pass : Buffer);varitem:Integer;始める cycle "永久ループで実行する" "アイテムを生成する" pass.put(item) "アイテムをモニターに渡す" 終わり 終わり; 「消費者はバッファを使用する」 consumer = process(pass : Buffer);varitem:Integer;始める サイクル pass.get(item); "モニターからアイテムを取得する" "アイテムを消費する" 終わり 終わり; 「モニター、プロデューサー、コンシューマーのインスタンスを宣言する」「プロデューサーとコンシューマーにモニターへのアクセス権を与える」 変数 パス: バッファ; prod:プロデューサー 短所:消費者向け 始める init pass, "モニターを初期化します" prod(pass), "プロデューサープロセスを開始します" cons(pass) "コンシューマープロセスを開始します" end.