ロックの競合状態を防ぐものは何ですか?


24

データ競合とは何か、そしてロック/ミューテックス/セマフォがそれらを防ぐのにどのように役立つのかを理解しています。しかし、ロック自体に「競合状態」がある場合はどうなりますか?たとえば、おそらく同じアプリケーション内にあるが、異なるプロセッサで実行されている2つの異なるスレッドが、まったく同時にロックを取得しようとします。

それではどうなりますか?それを防ぐために何が行われますか?それは不可能ですか、それともまったくありそうもないことですか?それとも、実際に発生するのを待っている競合状態ですか?


この質問は、SOの前に頼まれた:stackoverflow.com/questions/980521/...
ドク・ブラウン


ロックを取得してロックを取得します;)(つまり、ロックに競合状態がある場合、ロックは正しく実装されていません-ロックは相互排除を実装する構造体として定義されています)
Tangrs

ロックがどのように機能するかの重要なポイントを見逃しました。これらは、ロックで競合することができないように構築されています。そうしないと、完全に役に立たなくなります。
ゼーン14年

回答:


36

それは不可能ですか、それとも単なるありそうもないことですか?

不可能。さまざまな方法で実装できます。たとえば、ハードウェアが順次実行を保証するCompare-and-swapを介して実装できます。複数のコアまたは複数のソケットが存在する場合、少し複雑になる可能性があり、コア間に複雑なプロトコルが必要ですが、これはすべて処理されます。


3
ありがとう...神...それはハードウェアで処理されます...(または少なくとも私たちが触れるよりも低いレベルです。)
corsiKa

2
@gdhoward信じられない...この答えは5分もかからず、400の答えのうち3番目に高い票数でした(主にSO)。また、おそらく最も短いものです。
maaartinus

1
@maaartinus-短くて甘いことがあります。
ボブソン14年

17

アトミックな「テストと設定」操作の概念を研究します。

基本的に、操作を分割することはできません。2つのことをまったく同時に行うことはできません。値をチェックし、明確な場合は設定し、テスト時の値を返します。ロック操作では、テストと設定後の結果は常に「lock == TRUE」になります。唯一の違いは、開始時の設定かどうかです。

シングルコアプロセッサのマイクロコードレベルでは、これは分割できない1つの命令であり、簡単に実装できます。マルチコアプロセッサとマルチコアプロセッサを使用するのは難しくなりますが、プログラマーとして心配する必要はありません。シリコンを扱う本当に頭のいい人たちによって動作するように設計されています。本質的には同じことを行います-テストと設定の派手なバージョンであるアトミックな命令を作成します


2
基本的に、ハードウェアが本質的に特定のレベルでシーケンシャルでない場合、それ以外の場合に発生する可能性のある関係を壊すことができるメカニズムがあります。
ビルミシェル14年

@BillMichell、私はそれを考えるべきだった。実際、私はそうしました。私の仮定が正しいかどうかは知りませんでした。
ギャビンハワード14年

2

競合セクションが相互排除に違反しないように、特別に設計されたクリティカルセクションにコードを配置するだけです。

ほとんどの場合、ハードウェアレベルで実行されるアトミックな比較および設定ループが使用されます。

while(!CompareAndSet(&lock, false, true));//busy loop won't continue until THIS thread has set the lock to true
//critical section
CompareAndSet(&lock, true, false);

それがなければ、相互排除を可能にするためのよく研究されたソフトウェアソリューションがあります。


1

2つ(またはそれ以上)のスレッドが同時にロックを取得することはできません。たとえば、いくつかのタイプの同期方法があります。

アクティブ待機-スピンロック

擬似コード:

1. while ( xchg(lock, 1) == 1); - entry protocole

XCHGは、最初に「ロック」変数に新しい値を設定してから古い値を返すアトミック操作(x86アーキテクチャ上に存在する)の例です。アトミックとは、割り込みできないことを意味します-上記の例では、新しい値を設定してから古い値を返すまでの間です。アトミック-何があっても決定的な結果。

2. Your code
3. lock = 0; - exit protocol

ロックが0に等しい場合、別のスレッドがクリティカルセクションに入り、ループが終了します。

スレッドの中断-たとえば、セマフォのカウント

アトミック操作が2つ.Wait()あり.Signal()、整数変数を呼び出すことができますint currentValue

Wait():
if (currentValue > 0) currentValue -= 1;
else suspend current thread;

Signal():
If there exists thread suspended by semaphore wake up one of them
Else currentValue += 1;

クリティカルセクションの問題の解決は本当に簡単です。

擬似コード:

mySemaphore.Wait();
do some operations - critical section
mySemaphore.Signal();

通常、プログラミングスレッドAPIを使用すると、セマフォクリティカルセクションで最大同時スレッドを指定できます。明らかに、マルチスレッドシステムにはより多くの種類の同期(ミューテックス、モニター、バイナリセマフォなど)がありますが、それらは上記のアイデアに基づいています。スレッドのサスペンドを使用するメソッドは、アクティブな待機よりも優先されるべきであると主張することができます(CPUは無駄になりません)-常に真実とは限りません。スレッドが中断されている場合-コンテキストスイッチと呼ばれる高価な操作が実行されます。ただし、待機時間が短い場合(スレッドの数〜コアの数)が妥当です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.