スピンロックは「無駄」であるという質問が意味するように、スピンロックは短時間だけ保持する必要があります。
スピンロックは、複数のスレッドを同期する唯一の方法ではありません。 Linux カーネルでは、他の同期プリミティブ (waitqueue、イベントなど) と同様にミューテックス/セマフォも使用されます。
ただし、カーネルは、ユーザー空間が決して見ないケースに対処する必要があります。一般的なケースは、割り込みハンドラーです。 Linux では割り込みハンドラーを再スケジュールすることはできませんが、多くの場合、何らかの同期プリミティブを使用する必要があります (たとえば、他のスレッドがさらに処理するリンクされたリストに作業項目を追加するなど)。割り込みハンドラーはスリープできないため、ミューテックスやウェイトキューなどを使用できません。これにより、スピンロックがほとんど残ります。スレッドが割り込みハンドラーとアクセスを同期する必要がある場合は、同じスピンロックも使用する必要があります。
スピンロックは必ずしも無駄ではありません。それらは非競合/非待機ケース用に最適化されており、非常に迅速に取得および解放できます。その場合、他の同期プリミティブよりも高速でオーバーヘッドが少なくなります。
スピンロックと、呼び出し元が CPU の制御をブロックして放棄する原因となる別の構造との間の選択は、コンテキスト スイッチ (ロッキング スレッドでレジスタ/状態を保存し、レジスタ/状態を復元する) を実行するのにかかる時間によって大きく左右されます。別のスレッドで)。かかる時間と、これを行うためのキャッシュ コストは、かなりの量になる可能性があります。
ハードウェアレジスタへのアクセスを保護するためにスピンロックが使用されている場合、またはアクセスしている他のスレッドがロックを解放するまでに数ミリ秒以下しかかからない場合は、スピン待機に CPU 時間をより有効に使用できます。コンテキストを切り替えて続行するのではなく、
他の人が答えました。スピンロックを使用するケースと、スピンロックを使用するためのルールをまとめます。
1.スピンロックを使用する場合は?
回答:以下の状況で。
<オール>適切に使用すると、スピンロックはセマフォよりも高いパフォーマンスを提供できます。例:割り込みハンドラ。
2.スピンロックの使用規則は?
答え:
ルール - 1:スピンロックを保持しているコードは、割り込みを処理する場合を除いて、何らかの理由でプロセッサを解放することはできません (場合によっては解放されないこともあります)。そのため、スピンロックを保持するコードはスリープできません。
理由:スピンロックを保持しているドライバーがスリープ状態になったとします。例:関数 copy_from_user()
を呼び出します または copy_to_user()
、またはカーネルのプリエンプションが開始されるため、優先度の高いプロセスがコードを脇に押しやります。事実上、プロセスはスピンロックを保持している CPU を解放します。
コードがいつロックを解除するかはわかりません。他のスレッドが同じロックを取得しようとすると、非常に長い時間スピンします。最悪の場合、ディードロックが発生します。
カーネル プリエンプション ケースは、スピンロック コード自体によって処理されます。カーネル コードがスピンロックを保持している場合は常に、関連するプロセッサでプリエンプションが無効になります。ユニプロセッサ システムでも、この方法でプリエンプションを無効にする必要があります。
ルール - 2:スピンロックが保持されている間、ローカル CPU の割り込みを無効にします。
理由:デバイスへのアクセスを制御するスピンロックを取得し、割り込みを発行するドライバーをサポートします。これにより、割り込みハンドラが実行されます。現在、割り込みハンドラもデバイスにアクセスするためにロックが必要です。割り込みハンドラが同じプロセッサで実行されている場合、スピンが開始されます。また、ドライバー コードを実行してロックを解除することもできません。 SO プロセッサは永久に回転します。
ルール - 3:スピンロックは可能な限り最小限の時間保持する必要があります。
理由:ロック保持時間が長いため、現在のプロセッサがスケジューリングできなくなります。つまり、優先度の高いプロセスが CPU を取得するのを待たなければならない可能性があります。
そのため、カーネルのレイテンシ (プロセスがスケジュールされるまで待機する必要がある時間) に影響します。通常、スピンロックは、CPU がスレッド間のコンテックス スイッチを実行するのにかかる時間よりも短い時間保持する必要があります。