web-dev-qa-db-ja.com

いつpthread_spin_lockを使用するのが適切ですか(たとえば、pthreadミューテックスに対して)?

Pthread_spin_lockが使用可能な場合、いつそれを使用し、いつ使用しない方がよいですか?

つまり、pthreadミューテックスまたはpthreadスピンロックのいずれかを使用して、共有データ構造をどのように保護するかを決定するにはどうすればよいですか?

38
Lyke

短い答えは、非常に短い間隔でロックを保持することを計画している場合(たとえば、カウンターをインクリメントするだけの場合)、スピンロックの方が優れている可能性があり、競合はまれであると予想されますが、操作は十分に頻繁に発生しています。パフォーマンスのボトルネックになる可能性があります。 mutexに対するスピンロックの利点は次のとおりです。

  1. ロック解除時に、他のスレッドがロックを待っているかどうかを確認する必要はありません。ロック解除は、単一のアトミックな書き込み命令です。
  2. ロックをすぐに取得できない場合、スレッドはスリープ状態になりません。そのため、ロックが利用可能になるとすぐに、待ち時間を大幅に短縮してロックを取得できる場合があります。
  3. カーネル空間に入って他のスレッドをスリープまたはウェイクさせることによるキャッシュ汚染のリスクはありません。

ポイント1は常に有効ですが、カーネルに待機を依頼する前に、適切なmutex実装がまともな回数スピンする可能性があると考えると、ポイント2と3の有用性はやや低下します。

さて、長い答え:

スピンロックを使用する前に確認する必要があるのは、これらの潜在的な利点が1つのまれですが非常に実際の欠点よりも優れているかどうかです。つまり、ロックを保持するスレッドが、スケジューラーがロックを解放する前に割り込まれたときに何が起こるかです。これはもちろんまれですが、ロックが単一の変数インクリメント操作または他の何か同じように簡単に保持されている場合でも発生する可能性があります。この場合、ロックを取得しようとする他のスレッドは、ロックを保持しているスレッドがスケジュールされ、ロックを解放する機会があるまでスピンし続けます。 これは決して発生しない可能性がありますロックを取得しようとするスレッドの優先順位が、ロックを保持しているスレッドよりも高い場合。これは極端な場合ですが、優先順位が異なっていても、ロックの所有者が再度スケジュールされるまでに非常に長い遅延が発生する可能性があります。最悪の場合、この状況が始まると、できるだけ多くのスレッドをすばやくエスカレートできます。ロックを取得し、スピンを開始し、より多くのプロセッサ時間を占有し、ロックを解放する可能性のあるスレッドのスケジューリングをさらに遅延させます。

そのため、スピンロックには注意が必要です... :-)

スピンロックは「ビジー待機」ロックです。主な利点は、スレッドをアクティブに保ち、コンテキストの切り替えを引き起こさないことです。そのため、非常に短い時間だけ待機していることがわかっている場合(重要な操作が非常に速いため)、これによりパフォーマンスが向上する可能性があります。ミューテックスより。逆に、クリティカルセクションに長い時間がかかり、コンテキストの切り替えが望ましい場合、ミューテックスはシステムへの要求を少なくします。

TL; DR:場合によります。

14
Kerrek SB

パフォーマンスを向上させる最も安全な方法は、アダプティブミューテックスの2つのハイブリッドです。

システムに複数のコアがある場合、数千サイクル回転して、競合が少ないかまったくない場合の最良のケースを取得し、完全なミューテックスを使用して、競合する長いロックのために他のスレッドに譲ります。

両方のPOSIX(PTHREAD_MUTEX_ADAPTIVE_NP)とWin32(SetCriticalSectionSpinCount)には適応型ミューテックスがあり、多くのプラットフォームにはPOSIXスピンロックAPIがありません。

7
Steve-o

スピンロックは、MPコンテキストにのみ関心があります。疑似原子タスクを実行するために使用されます。モノプロセッサシステムでは、原理は次のとおりです。

  1. スケジューラをロックします(タスクが割り込みを処理する場合は、代わりに割り込みをロックします)
  2. 私の原子的なタックを行います
  3. スケジューラーをアンロックする

ただし、MPシステムでは、他のコアがコードセクションに入る可能性のある他のスレッドを実行しないという保証はありません。これを防ぐために、スピンロックが作成されました。その目的は、他のコアの実行が同時実行の問題を防止しています。クリティカルセクションは次のようになります:

  1. スケジューラーをロックする
  2. SpinLock(他のコアの侵入を防ぐ)
  3. 私の仕事
  4. SpinUnlock
  5. タスクのロック解除

タスクロックが省略されている場合、スケジューリング中に、他のスレッドがセクションに入ろうとする可能性があり、100%CPUでループして次のスケジューリングを待機します。このタスクが優先度の高いものである場合、デッドロックが発生します。

1
Sebastien Kurz