スピンロックはスピニングで機能し、さまざまなカーネルパスが存在し、カーネルはプリエンプティブであることがわかっています。それでは、なぜスピンロックがユニプロセッサシステムで機能しないのでしょうか。(たとえば、Linuxの場合)
5 に答える
私があなたの質問を理解しているなら、あなたはなぜスピンロックがシングルコアマシンで悪い考えであるかを尋ねています。
それらはまだ機能するはずですが、真のスレッドスリープ同時実行よりもはるかに高価になる可能性があります。
スピンロックを使用する場合、基本的には、長く待つ必要はないと考えていることになります。あなたは、スレッドをスリープさせて別のスレッドまたはプロセスにコンテキストシフトするコストよりも、ビジーループでプロセッサタイムスライスを維持する方が良いと考えていると言っています。非常に短い時間待つ必要がある場合は、ほとんどすぐに眠って目覚めることができますが、上下するコストは、ただ待つよりも高くつきます。
マルチコアプロセッサはシングルコアプロセッサよりもはるかに優れた同時実行性プロファイルを備えているため、これはマルチコアプロセッサで問題ない可能性が高くなります。マルチコアプロセッサでは、ループの反復の合間に、他のスレッドが前提条件を処理している可能性があります。シングルコアプロセッサでは、他の誰かがあなたを助けてくれる可能性はありません-あなたは唯一のコアをロックしました。
ここでの問題は、ロックで待機またはスリープしている場合、必要なものがまだすべて揃っていないことをシステムに示唆するため、他の処理を行って後で戻ってくる必要があることです。スピンロックを使用すると、システムにこれを通知することはないため、他の何かが発生するのを待ってシステムをロックします。ただし、その間、システム全体を保持しているため、他の何かが発生することはありません。
スピンロックの性質は、プロセスのスケジュールを解除しないことです。代わりに、プロセスがロックを取得するまでスピンします。
ユニプロセッサでは、すぐにロックを取得するか、永久にスピンします。ロックが競合している場合、現在リソースを保持しているプロセスがそれを放棄する機会はありません。スピンロックは、あるプロセスがロックでスピンしているときに別のプロセスを実行できる場合にのみ役立ちます。つまり、マルチプロセッサシステムです。
スピンロックにはさまざまなバージョンがあります。
spin_lock_irqsave(&xxx_lock, flags);
... critical section here ..
spin_unlock_irqrestore(&xxx_lock, flags);
この場合、IRQも無効になるため、 Uniプロセッサspin_lock_irqsave()
では、データをプロセスコンテキストと割り込みコンテキストの間で共有する必要がある場合に使用する必要があります。spin_lock_irqsave()
すべての状況で動作しますが、安全であるという理由もあり、かなり低速です。ただし、異なるCPU間でデータを保護する必要がある場合は、以下のバージョンを使用することをお勧めします。この場合、IRQが無効にならないため、これらのバージョンは安価です。
spin_lock(&lock);
...
spin_unlock(&lock);
ユニプロセッサシステムでは、呼び出しspin_lock_irqsave(&xxx_lock, flags);
は割り込みを無効にするのと同じ効果があり、不要なSMP保護なしで必要な割り込み同時実行保護を提供します。ただし、マルチプロセッサシステムでは、これは割り込みとSMPの同時実行性の問題の両方をカバーします。
スピンロックは、その性質上、マルチプロセッサシステムでの使用を目的としていますが、同時実行性に関する限り、プリエンプティブカーネルを実行するユニプロセッサワークステーションはSMPのように動作します。非プリエンプティブユニプロセッサシステムがロックでスピンした場合、それは永久にスピンします。他のスレッドは、ロックを解放するためにCPUを取得することはできません。このため、プリエンプションが有効になっていないユニプロセッサシステムでのスピンロック操作は、IRQマスキングステータスを変更するものを除いて、何もしないように最適化されています。プリエンプションのため、コードがSMPシステムで実行されることを予期しない場合でも、適切なロックを実装する必要があります。
参照:Linuxデバイスドライバー Jonathan Corbet、Alessandro Rubini、Greg Kroah-Hartma
オペレーティングシステムの次の2つの段落を見つけてください。役立つかもしれない3つの簡単な部分:
スピンロックの場合、単一のCPUの場合、パフォーマンスのオーバーヘッドは非常に苦痛になる可能性があります。ロックを保持しているスレッドがクリティカルセクション内で横取りされる場合を想像してみてください。次に、スケジューラーは1つおきのスレッドを実行し(他にN − 1個あると想像してください)、それぞれがロックを取得しようとします。この場合、これらの各スレッドは、CPUを放棄する前に、タイムスライスの期間中スピンします。これは、CPUサイクルの浪費です。
ただし、複数のCPUでは、スピンロックは適切に機能します(スレッドの数がCPUの数とほぼ等しい場合)。考え方は次のとおりです。CPU1のスレッドAとCPU2のスレッドBを想像してみてください。どちらも、ロックを争っています。スレッドA(CPU 1)がロックを取得し、次にスレッドBがロックを取得しようとすると、Bは(CPU 2で)スピンします。ただし、おそらく重要なセクションが短いため、すぐにロックが使用可能になり、スレッドBによって取得されます。この場合、別のプロセッサでロックが保持されるのを待つためにスピンしても、多くのサイクルが無駄になることはありません。効果的である可能性があります