共有資源を同時に使えるプロセス数をカウンタで制御する仕組み。
セマフォとは、共有資源(=複数のプロセスが取り合う、数の限られた資源)を同時に使えるプロセス数をカウンタ S で制御する仕組みのことです。プロセスとは、実行中のプログラムのことだと考えてください。
身近な例で考えると、レンタル品の貸出カウンタに似ています。「貸し出せる残り個数」を示す札(=カウンタ S)があり、借りるたびに札の数を1減らし、返すたびに1増やします。残りが0なら、次の人は誰かが返すまで待つことになります。
上のツールで▶ボタンを押すと、S=1の資源を2つのプロセスがP操作・V操作で順番に使い、ぶつからずに資源を共有する流れを確認できます。
プロセスがセマフォに対して行う操作は2つだけです。資源を使うときのP操作(獲得)と、使い終わったときのV操作(解放)です。
P操作: S-- / V操作: S++
それぞれの動きは次のとおりです。
・P操作(獲得):S を1減らす(S--)。引いた後のSが0以上なら資源を獲得。負になったらそのプロセスは待機する
・V操作(解放):S を1増やす(S++)。待機中のプロセスがあれば1つ起こす
Sが負のときの絶対値は「待っているプロセスの数」を表します。S=1なら1つだけが使える(バイナリセマフォ)、S=nなら同時にn個まで使える(カウンティングセマフォ)という違いがあります。上のツールでP1のP操作・V操作に合わせてS値が増減する様子を見てみてください。
セマフォは、複数のプロセスが同じ資源を同時にいじってデータが壊れるのを防ぐために使われます。同時に触ると危険な処理区間をクリティカルセクションと呼び、ここに同時に複数のプロセスが入らないようにします。
代表的な用途は次のとおりです。
・排他制御:S=1のセマフォで、一度に1つのプロセスだけがクリティカルセクションに入れるようにする
・生産者消費者問題:データを作る側(生産者)と使う側(消費者)の歩調を合わせる
・資源の同時利用数制限:S=nのセマフォで、同時に使える数を最大n個に制限する
たとえば銀行口座の残高を2つの処理が同時に書き換えると、片方の更新が消えてしまうことがあります。セマフォで「一度に1つだけ」と決めておけば、こうした取り違えを防げます。上のツールで、P1が使っている間はP2が待たされ、解放されてからP2が進む様子を確認してください。
排他できる理由は「Sが負になったらブロック」というルールにあります。順を追って見ていきましょう。
① P1がP操作:S を 1→0 に減らし、資源を獲得します。S が 0 以上なので待たずに進めます。
② P2がP操作:S を 0→-1 に減らします。S が負になった瞬間、OS はP2を待機キュー(=順番待ちの列)に入れて停止させます。だから P2 は資源に触れません。
③ P1がV操作:S を -1→0 に増やします。OS は待機キューを見て、P2 を起こします。P2 が次に資源を使える状態になります。
このように、P操作とV操作は必ずセットで使うことが大切です。P操作だけしてV操作を忘れると、待機中のプロセスが永遠に起きられません(デッドロック=互いに待ち続ける状態)。V操作が「出口の鍵を返す」役割を果たしているイメージです。
セマフォには初期値の違いによって2種類あります。
バイナリセマフォ(初期値 S=1):Sが 0 か 1 しかとりません。「一度に1つのプロセスだけ」という排他制御に使います。トイレの鍵(空き/使用中の2状態だけ)のイメージです。
カウンティングセマフォ(初期値 S=n):Sが 0〜n の間で変化します。「同時にn個まで使える」という資源数の制限に使います。駐車場の「残り台数」カウンタのイメージです。3台分あれば3台まで同時に駐車でき、満車(S=0)になったら次の車は待つことになります。
| 種類 | 初期値 | 同時利用 | 用途 |
|---|---|---|---|
| バイナリ | S = 1 | 1つだけ | 排他制御(データ破壊防止) |
| カウンティング | S = n | 最大n個 | 資源数の制限・生産者消費者問題 |