排他制御の方法であるセマフォとミューテックスについてみていきます。
セマフォとミューテックスは似たところもある機能ですが、違いもいろいろありますので、その点もまとめていきます。
セマフォ
セマフォの基本的な動作は以下の通りとなります。
- 資源が何個同時にアクセスしてもよいかを定義し、セマフォのカウントとする
- 資源を使用する直前にセマフォを取得する
(このとき、セマフォのカウントが-1される) - 資源を使用し終わったらセマフォを解放する
(このとき、セマフォのカウントが+1される) - 資源の同時アクセスの上限に達しているとき、資源が解放されるまで待つ
(セマフォのカウントが0のとき、1以上になるまで待つ)
資源の数とセマフォのカウントが一致していて、セマフォのカウントを見ることによって資源の残りの数が確認できるという仕組みです。資源が余っていない場合は使用できるようになるまで待つことになります。
もう少し具体的な例として見てみましょう。
- 資源は2個分用意する。このとき、セマフォの値は2
- Aが資源を使用するためにセマフォを取得する。このとき、セマフォの値は2から1になる
- Bが資源を使用するためにセマフォを取得する。このとき、セマフォの値は1から0になる
- Cが資源を使用するためにセマフォを取得しようとする。しかし、セマフォの値が0なので、取得できず待ち状態となる
- Aが資源を使用し終わったので、セマフォを解放する。このとき、セマフォの値は0から1になる
- セマフォの値が1になったので、Cはセマフォを取得し、資源を使用することができる。このとき、セマフォの値は1から0になる
といったような動作となります。
組み込みで使用する場合は、パラメータの同時アクセスを禁止する目的で使用することが多いです。
したがって、セマフォの初期値は1になります。
この用途で使用する場合、以下のことを守る必要があります。
- 同じ資源を使用するタスクの中で最も優先度が高いものよりも優先度を高くしてからセマフォを取得する
- クリティカルセクション(※)はできるだけ短くする
- セマフォ中に別のセマフォを取得しない
※クリティカルセクションとは、複数の処理が同時に実行されると問題が発生する箇所のことで、この場合はセマフォを取得している区間を指す
これを守らない場合、以下の問題が発生する可能性があります。
- 優先度が高いタスクの時間的制約が守れない
- デッドロックが発生する
1つ目の時間的制約が守れない、というのは、「優先度を高くする」と「クリティカルセクションを短くする」に関連しています。
優先度を変更しない場合、優先度が低いタスクが先にセマフォを取得してしまうと、そのタスクの処理が完了するまで優先度が高いタスクの処理が待たされてしまう可能性があります。
2タスク間の間だけの話であればクリティカルセクション分だけ待たされるだけで済むのですが、関係のないタスクがもう1つ登場するだけで、以下の図のような長時間待たされるケースが発生する可能性があります。

タスクAがセマフォの解放を待っているのに対し、セマフォを取得しているタスクCよりも優先度の高いタスクBによってタスクCが動作できず、長時間セマフォが解放されないというケースです。
本来であればタスクCのクリティカルセクション分の待ちだけで済むはずだったのに、タスクBの処理の長さ分だけタスクAの処理の完了が遅くなってしまいます。
こういったケースを防ぐためにクリティカルセクション区間中は優先度をタスクAよりも大きくして処理を早く終わらせるべき、ということです。
なお、タスクAの処理はどうやってもクリティカルセクション分だけ遅延する可能性は残るので、遅延の時間をできるだけ小さくするためにクリティカルセクションの区間をできるだけ小さくする必要があります。
2つ目のデッドロックについては、2つのタスクで2つのセマフォを取得するときに発生する可能性があります。
タスクAはセマフォAを取得しつつセマフォBの解放を待っていて、タスクBはセマフォBを取得しつつセマフォAの解放を待つ、という状態になってしまうと、どちらのセマフォも解放されないままになってしまってその後の処理ができない状態となってしまいます。

これは優先度を上げることと、セマフォ取得中に別のセマフォを取得しないということを守れば発生しないはずなので、そうならないように設計しましょう。
ミューテックス
セマフォはアクセスできる資源の数を指定できたのに対し、ミューテックスはクリティカルセクションに入れるタスクは1つのみ、という制約があります。
ですので、セマフォのアクセス資源数が1のときと動作がほとんど一緒です。
ただし、ミューテックスの場合は、セマフォで説明してきた優先度逆転の現象を防ぐために自動的に優先度を変更する機能や、デッドロックを防ぐための優先度上限プロトコルが含まれていることもあります。
これらの機能が含まれたミューテックスを使う場合は、セマフォで注意した点を気にせず実装することができます。
もちろん、これらの機能が含まれないケースもあるので、ミューテックスの機能を確認してから使用するようにしましょう。
まとめ
以上、セマフォとミューテックスについてまとめました。
クリティカルセクションの排他処理をする場合であれば、ミューテックスが使用できるならばミューテックスの方が便利でしたね。
ただ、私はあまり使用したことがないですが、セマフォの方は複数の資源が使用できるという点がポイントなので、セマフォとミューテックスは状況に応じて使い分けていただければよいでしょう。