web-dev-qa-db-ja.com

スレッド競合とは何ですか?

誰かがスレッドの競合とは何かを簡単に説明できますか?

私はそれをグーグルで調べましたが、簡単な説明を見つけることができないようです。

95
Tony The Lion

基本的に、スレッドの競合とは、あるスレッドが別のスレッドによって現在保持されているロック/オブジェクトを待機している状態です。したがって、この待機スレッドは、他のスレッドがその特定のオブジェクトのロックを解除するまで、そのオブジェクトを使用できません。

69
keyboardP

いくつかの答えはロックの競合に焦点を当てているようですが、競合が発生する可能性のあるリソースはロックだけではありません。競合とは、競合するスレッドの少なくとも1つが他のスレッドが実行されていない場合よりも遅くなるように、2つのスレッドが同じリソースまたは関連するリソースにアクセスしようとすることです。

競合の最も明白な例は、ロックに関するものです。スレッドAにロックがあり、スレッドBが同じロックを取得する場合、スレッドBはスレッドAがロックを解除するまで待機する必要があります。

現在、これはプラットフォーム固有ですが、他のスレッドがロックを解除するのを待たなくても、スレッドがスローダウンする可能性があります!これは、ロックが何らかの種類のデータを保護し、データ自体もしばしば競合するためです。

たとえば、ロックを取得し、オブジェクトを変更してからロックを解除し、他のことを行うスレッドを考えます。 2つのスレッドがこれを実行している場合、たとえロックのために競合しないとしても、1つのスレッドのみが実行されている場合よりもスレッドの実行がはるかに遅くなる可能性があります。

どうして?各スレッドが最新のx86 CPU上の独自のコアで実行されており、コアがL2キャッシュを共有していないとします。スレッドが1つだけの場合、ほとんどの場合、オブジェクトはL2キャッシュに残る可能性があります。両方のスレッドが実行されていると、一方のスレッドがオブジェクトを変更するたびに、他方のCPUがキャッシュラインを無効化したため、他方のスレッドはデータがL2キャッシュにないことを検出します。たとえば、Pentium Dでは、コードがFSB=速度で実行されます。これは、L2キャッシュの速度よりはるかに低速です。

ロック自体が競合しない場合でも競合が発生する可能性があるため、ロックがない場合にも競合が発生する可能性があります。たとえば、CPUが32ビット変数のアトミックインクリメントをサポートしているとします。 1つのスレッドが変数をインクリメントおよびデクリメントし続けると、変数はキャッシュ内で頻繁にホットになります。 2つのスレッドがそれを行うと、キャッシュはその変数を保持しているメモリの所有権を奪い合い、キャッシュコヒーレンシープロトコルがキャッシュラインの各コア所有権を保護するように動作するため、多くのアクセスが遅くなります。

皮肉なことに、ロックは通常reduce競合です。どうして?ロックがないと、2つのスレッドが同じオブジェクトまたはコレクションで動作し、多くの競合が発生する可能性があるためです(たとえば、ロックフリーキューがあります)。ロックは競合するスレッドをスケジュール解除する傾向があり、競合しないスレッドを代わりに実行できます。スレッドAがロックを保持し、スレッドBが同じロックを必要とする場合、実装は代わりにスレッドCを実行できます。スレッドCがそのロックを必要としない場合、スレッドAとBの間の将来の競合はしばらく回避できます。 (もちろん、これは実行可能な他のスレッドがあることを前提としています。システム全体が有益な進歩を遂げる唯一の方法が競合するスレッドを実行することである場合は役に立ちません。)

164
David Schwartz

ここ から:

すぐに利用できないリソースをスレッドが待機しているときに競合が発生します。コードの実行は遅くなりますが、時間が経つと解消されます。

デッドロックは、スレッドが2番目のスレッドがロックしたリソースを待機しており、2番目のスレッドが最初のスレッドがロックしたリソースを待機しているときに発生します。 3つ以上のスレッドがデッドロックに関与する可能性があります。デッドロックは決して解決しません。多くの場合、アプリケーション全体、またはデッドロックが発生している部分が停止します。

18
Jon B

私は質問の背景にOPからいくつかの明確化があるはずだと思います-私は2つの答えを考えることができます(このリストに追加があると確信していますが):

  1. スレッド競合の一般的な「概念」と、それがアプリケーションでどのように表示されるかについて言及している場合は、上記の@DavidSchwartzの詳細な回答に従うことにします。

  2. 「.NET CLR Locks and Threads:Total#of Contentions」パフォーマンスカウンターもあります。このカウンタのPerfMonの説明から得られるように、次のように定義されます。

    このカウンターは、CLRのスレッドが管理されたロックの取得に失敗した合計回数を表示します。管理されたロックは、多くの方法で取得できます。 C#の「ロック」ステートメントによって、またはSystem.Monitor.Enterを呼び出すか、MethodImplOptions.Synchronizedカスタム属性を使用して。

...そして、他のOSやアプリケーションフレームワークのための他の人もきっと確信しています。

3
Dave Black

2つのスレッドがあります。スレッドAとスレッドBには、オブジェクトCもあります。

Aは現在オブジェクトCにアクセスしており、そのオブジェクトにロックをかけています。 BはオブジェクトCにアクセスする必要がありますが、AはオブジェクトCのロックを解除するまでアクセスできません。

2
Aaron M

別の言葉は並行性かもしれません。これは、同じリソースを使用しようとする2つ以上のスレッドのアイデアです。

1
Mark Wilkins

次のシナリオを想像してください。あなたは明日の最終検査の準備をしていて、少しお腹が減っています。ですから、弟に10ドルを渡して、あなたにピザを買ってもらうように頼みます。この場合、あなたはメインスレッドであり、兄弟は子スレッドです。注文が与えられると、あなたとあなたの兄弟の両方が同時に仕事をしています(つまり、ピザの勉強と購入)。ここで、考慮すべき2つのケースがあります。最初に、あなたの兄弟がピザを持ち帰り、勉強中に終了します。この場合、勉強をやめてピザを楽しむことができます。第二に、ピザが利用できるようになる前に、勉強を早く終えて眠ります(つまり、今日の割り当てられた仕事-明日の最終試験のための勉強が完了します)。もちろん、眠ることはできません。そうしないと、ピザを食べる機会がありません。あなたがやろうとしているのは、あなたの兄弟がピザを取り戻すまで待つことです。

例のように、2つのケースはライバル関係の意味を与えます。

1
snr

競合は、共有リソースを介した2つ以上のスレッド間の競合です。リソースは、ロック、カウンターなどです。競争とは、「誰が最初に取得するか」を意味します。スレッドが多いほど、競合が増えます。リソースへのアクセス頻度が高いほど、競合が多くなります。

1
Maciej

スレッドの競合は、I/O操作の影響も受けます。ファイルの読み取りを待機しているスレッドが競合と見なす場合の例。 I/O完了ポートをソリューションとして使用します。

0
amilamad

スレッドが他のスレッドによってすでに取得されているオブジェクトへのロックを取得しようとすると、ロックの競合が発生します*。オブジェクトが解放されるまで、スレッドはブロックされます(つまり、待機状態になります)。場合によっては、これはいわゆるシリアル実行につながり、アプリケーションに悪影響を与える可能性があります。

from dotTrace documentation

0
AndreyT