質問: カーネル内の実装について、普段プログラマはセマフォやロックを用いて排他制御を行うと思うのですが、これらのセマフォやロックの実装について勉強致しました。 その結果、スピンロックという手法が取られていることがわかりました。ビジーウエイトによる実装ということがわかりました。そこで二つほど疑問ができました。 こちらのサイトを見る限りだと、そもそもカーネルの割り込みをさせないことが前提になっています。 つまりこれらの処理は単一プロセサに対しては割り込みさせないという処理が大前提になっているのでしょうか? またスピンロックはあくまでロックの獲得の1手法であり、スピンロックのみ使えばロックが安全に取れる(マルチプロセサ環境で)ということはありませんよね? よろしくお願いいたします。
回答: こんにちは。 > > こちらのサイトを見る限りだと、そもそもカーネルの割り込みをさせないことが前提になっています。 > > つまりこれらの処理は単一プロセサに対しては割り込みさせないという処理が大前提になっているのでしょうか? > > > アトミック命令を使ってロックを取得できるので、別に割り込みを禁止する必要はないと思います。アトミック命令実行中に割り込みはかかりませんから。 実際の実装を見たことはないですが、恐らくアトミック命令を使えるプロセッサでは態々割り込み禁止していない筈です。 昔は、ロック取得に使えるようなアトミック命令がないシングル・プロセッサが主流でしたので、割り込み禁止して対応してました。 あと、リンク先の図9は一見アトミック命令でロック確保できるまでビジー・ウェイトするようにも読み取れますが、書きにくかったのだろうと思います。 そのような実装は非常に危険(ロック解放されなければCPUはアトミック命令から抜け出せない)なので、実際に使われるケースはあまりない筈です。 1. ロック変数をチェックしてアンロックならロックする 2. ロックを取得できなかったら、1.をリトライする 1.がアトミック命令で実行され、2.の処理は別の命令に分かれていると思います。 > > またスピンロックはあくまでロックの獲得の1手法であり、スピンロックのみ使えばロックが安全に取れる(マルチプロセサ環境で)ということはありませんよね? > > > ロックを取得する方法とロック取得のリトライ操作は分けて考えた方が良いです。 ロックを取得できなかった場合、ロック取得をリトライする場合が多いですが、その時、直ぐにリトライするのがスピン・ロックですね。CPUを無駄に消費するのであまり使われないと思います。 一定時間スリープしてリトライすることも考えられます。ポーリングと呼ばれます。応答時間とCPU消費のトレード・オフになりますが、デッドロックを避けやすいです。(待ちの間に処理を挟めますので。) そして、他のイベントの発生によりリトライする方法が最も良く使われます。例えば、ミューテックスの場合はミューテックス解放イベントによりロック取得をリトライします。CPUを無駄に消費しないので効率的です。しかし、待っている間何もできないため、デッドロックを避けるのが結構たいへんです。 【スピンロック補足】 もしかすると、セマフォやミューテックスを実装する際に使われている場合もあるかも知れません。 セマフォやミューテックス自身がアトミックにアクセスできないくらい多くのメモリを使うような場合、それらを一旦ロックする必要があります。使うメモリが多少多めとは言え、数命令でアクセスが完了する筈なので一旦CPUを解放するより、ビジー・ウェイトした方が効率が良い場合がありますので。