スピンロックとミューテックスの違い:待ち方・CPU使用・保持時間・カーネルでの使い方を比較
スピンロックとミューテックスは、どちらも臨界区間に同時に1つのスレッドだけを入れるロックですが、ロックが空くのを待つ方法が違います。スピンロックは、ループでロックの変数を調べ続けるビジーウェイトで待つので、待つ間もCPUを使い続けますが、空いたらすぐに取れます。ミューテックスは、待つスレッドをスリープさせてCPUを手放し、ロックが解放されたらOSに起こしてもらいます。保持時間がごく短い場合や眠れない割り込みハンドラの中ではスピンロック、長く保持する場合や保持中に眠る可能性がある場合はミューテックスを使います。
| 項目 | スピンロック | ミューテックス |
|---|---|---|
| 待ち方 | ロックが空くまで、ループで変数を調べ続ける(ビジーウェイト) | 空いていなければスリープして待ち、解放されたときに起こしてもらう |
| 待つ間のCPU | 使い続ける | 手放す。その間、ほかのスレッドがCPUを使える |
| 待ちの手間 | コンテキストスイッチがなく、空いたらすぐに取れる | 眠るときと起きるときに、システムコールとコンテキストスイッチの手間がかかる |
| 向いている保持時間 | ごく短い時間(コンテキストスイッチにかかる時間より短い) | 長い時間。保持中にI/Oを待つなど、眠る可能性があるとき |
| 保持中に眠ること | してはいけない。待つ側がCPUを使い続けることになる | できる |
| コアが1つのとき | 待つ間はロックを持つスレッドが動けず、回っても空かない。カーネルではプリエンプションを止めて使う | 問題なく使える |
| カーネル内での使い方 | 割り込みハンドラのような眠れない場面(割り込みコンテキスト)でも使える。割り込みとデータを共有するときは、割り込みを禁止してから取る | 眠る可能性があるので、プロセスコンテキストでだけ使え、割り込みハンドラでは使えない |
| 優先度逆転 | ロックを持つスレッドが止められると、待つ側が回り続けてしまう。カーネルでは保持中のプリエンプションを禁止して防ぐ | 優先度継承つきのミューテックスで対策できる |
| 実装の例 | アトミック命令(test-and-setやcompare-and-swap)で変数を書き換える。普段は通常の読み出しで待つtest-and-test-and-setで、コア間の通信を減らす | Linuxのfutexでは、競合がなければユーザ空間のアトミック命令だけでロックし、競合したときだけカーネルに眠らせてもらう。少し回ってから眠る実装もある |
数値は代表的な目安で、世代や製品によって異なります。