mutexとよばれるデータを生成して返す.このデータはロックされているかど うかの状態を持っており,相互排除と同期のための関数で使用される.
〈mutex〉をロックする.すでに〈mutex〉がロックされている 場合は解除されるまでサスペンドして待つ.複数のプロセスが同時に同一の 〈mutex〉をロックしようとすると,1つのプロセスだけがロックに成 功し,それ以外のプロセスは解除されるまでサスペンドする.返す値は #tである.
〈mutex〉のロックを解除する.そして〈mutex〉のロックが解 除されるのを待っているプロセスがあれば,そのうちの1つを再開する.返す 値は #tである.
(condition-wait 〈 mutex〉) 【関数】
condition-waitは,他のプロセスがある条件を満たすまでプロセスをサ スペンドために使用する.サスペンドしているプロセスに条件が成立したこと を通知するには, condition-signal
[2]を使用する. condition-wait式を評価するとまず〈mutex〉 のロックを解除する.そしてこの〈mutex〉を引数に condition-signalが実行されるまで,この式を評価したプロセスはサスペン ドする. condition-signalの実行によってプロセスが再開すると condition-wait式を評価したプロセスは再び〈mutex〉 をロックしようとする.ロックに成功すると condition-signalによって 与えられた値を condition-wait式の値として返す.
(condition-signal 〈 mutex〉〈データ〉) 【関数】
〈mutex〉を引数として condition-waitを実行してサスペ ンドしているプロセスのうちの1つを起こす. condition-signalによっ て実行を再開したプロセスは condition-wait式の値として〈デー タ〉を受け取る.返す値は〈データ〉である.
あるプロセスが mutex-lockによって保護された領域を実行している間は, 他のプロセスはその領域に入ることができない.もし,そのような領域の実行 中にこの領域での他のプロセスによる処理を待たなければならない場合は,デッ ドロックに陥る.そこで condition-waitを用いて,他のプロセスによる 処理が終了するまでサスペンドし, mutex-lockによって保護された領域 への進入を許すことによりデッドロックを避けることができる.
condition-waitは,通常以下の形で使用される.
(mutex-lock m)![]()
(while (condition-wait m))![]()
(mutex-unlock m)
(mutex-lock m)![]()
(while 条件が満たされない
(condition-wait m))![]()
(mutex-unlock m)
図21.1に,同期を取るための関数の使用例として,有 限バッファを用いた生産者と消費者の問題を示す.この例ではバッファへのデー タの追加,取り出しの操作を排他的に行なうためにmutexオブジェクトを使用 している.データを追加するときにバッファが一杯ならば,バッファに空きが できるまで待つ必要がある.またデータを取り出す時にバッファが空であれば, バッファにデータが追加されるまで待つ必要がある.そこでこのような場合は, condition-waitを使ってバッファに空きができるまで(あるいはデータ が追加されるまで)待つ.そしてバッファに空きができたときやバッファが空 になったときに, condition-signalによってそのことを伝える.
これは
(let ((lock (make-mutex)))と等価である. exlambda式によって作られた関数閉包は同 時に複数のプロセスによって実行されることがないので,相互排除を必要とす る関数を実現することができる.
(lambda (《λリスト》)
(let ((r '()))
(mutex-lock lock)
(set! r (begin 《本体》))
(mutex-unlock lock)
r)))
プロセス・クロージャとよばれる関数閉包を返す.プロセス・クロージャは 《本体》を実行するためのプロセスとプロセス・クロージャへの引数 を格納するためのキューを持っている.プロセス・クロージャが呼び出される と,それを呼び出したプロセスはpromiseを生成し,それを引数と一緒にキュー に入れる.そしてプロセス・クロージャの呼び出し以降の処理を続ける.プロ セス・クロージャに付随するプロセスはキューからpromiseと引数を受け取り 《本体》を評価する.そしてpromiseの値を《本体》の値に 決定する.プロセス・クロージャは exlambda式によって生成された関数 閉包と同様に,同時に複数のプロセスによって実行されることがない.しかし exlambda式による関数閉包と異なり,プロセス・クロージャを呼び出し たプロセスは《本体》の値が必要になるまで実行を先に進めることが できる.