セマフォ
セマフォ変数の重要な属性として、その値の変更には特定の関数群を使わなければならないという点が挙げられる。ここではそれらの関数を wait() と signal() とする。
カウンティングセマフォでの2つの操作は、歴史的には V(または signal())と P(または wait())と記述される。V操作はセマフォSをインクリメントし、P操作はデクリメントする。角括弧で囲まれた部分は不可分操作であることを意味し、その部分の途中経過は他の実行単位からは見えない。
セマフォSの値は、その時点で使用可能な資源の個数である。P操作は資源を獲得しようとするもので、セマフォで守られている資源が使用可能になるまでビジーウェイトまたはスリープ(英語版)で待つことになる。V操作はその逆であり、使用していた資源を解放する。
wait() と signal() を簡単に説明すると次のようになる。
wait(): セマフォの値を1だけデクリメントする。その結果、値が負になるなら wait() を実行している実行単位はブロックされる。つまり、セマフォの待ちキューに追加される。
signal(): セマフォの値を1だけインクリメントする。その後、インクリメント前の値が負だったら(つまり資源待ち状態の実行単位があるなら)、セマフォの待ちキュー上にあるブロックされた実行単位をレディ(実行可能)キューに移す。
多くのOSは効率的なセマフォのプリミティブを提供しており、セマフォをインクリメントした際には1つだけ待ち状態の実行単位をアンブロックする。すなわち、複数の実行単位を同時にアンブロックした際の無用なセマフォ値のチェック処理を防いでいる。
POSIX準拠の環境では、semaphore.hに宣言された型と関数を使用できる。sem_init()で無名のセマフォを生成するか、sem_open()で名前付きセマフォを生成またはオープンできる。sem_init()の引数psharedに非ゼロの値を指定することで、プロセス間で共有されるセマフォを生成することもできる。sem_wait()でセマフォの値を減らし(ロック)、sem_post()でセマフォの値を増やす(ロック解除)。sem_destroy()で無名のセマフォを破棄する。sem_close()で名前付きセマフォをクローズする。