私は現在、Anthony WilliamsによるC++ Concurrency in Actionを読んでおり、思考の障害に直面しています。
最初に、彼はデッドロックを2つのスレッドが同時にロックするときとして説明します(少なくとも、それが私が理解した方法です)。これは理にかなっています。
ただし、彼は続けて、2つのミューテックスを同時にロックする方法について説明します。明らかにこれには機能がありますが、上記の(おそらく間違っている)理解により、両方のスレッドが即座にデッドロックになります。
その障害から新しい障害が発生します。明らかにデッドロックは発生しません。つまり、ミューテックスは、単一のスレッドがプロセスで作業できるようにするだけでなく、より高度な使用法が必要です。この本では、ミューテックスは特定のオブジェクトに与えられています。
これは私の全体的な質問につながります:ミューテックスは特定のメモリ領域に割り当てられていますか、オブジェクトなど?もしそうなら、どのように?
この本は、ミューテックスの使用方法を説明するのに優れていますが、ミューテックスが低レベルにあることを実際に説明することはありません。私はそれらが実装固有であることを認識していますが、それらが正確に何をするのか、またはロック関数がそれらをどのように使用するのかを実際には理解していません。
ミューテックスは特定のメモリ領域ではありません。これはシグナルであり、基本的には特殊なタイプのオブジェクトであり、いわば「名誉システム」で純粋に機能します。ミューテックスは、コードとの固有の関係があるためではなく、問題のコードを呼び出すためにコードの領域を保護します。 (C#のlock
キーワードのように、オブジェクトに関連付けられたロックであっても、ロックはコードの一部によって呼び出された場合にのみ機能します。)
コードの一部がロックを取得しようとすると、2つのことが発生する可能性があります。それは、使用可能なロックを見つけてロックを取得するか、すでに使用されていることを見つけて失敗するかです。失敗に対する最も一般的な応答は、ロックが使用可能になるまで待つことです。また、2つのスレッドが両方とも同時にロックを使用しようとしているため、デッドロックは発生しません。これは、2つのスレッドが両方とも同時にwaiting on each other
であるために発生します。
A
とB
という名前の2つのロックが存在し、1と2という名前の2つのスレッドが存在するとします。どちらもA
とB
の両方へのロックされたアクセスを必要とする処理を実行していますが、スレッド1はA
を保持し、スレッド2はB
を保持します。両方がもう一方のロックを取得しようとした後、(通常どおり)それが使用可能になるまで永久に待機しようとすると、両方が永久に待機し続けます(デッドロック)。
このような状況を防ぐ最善の方法は、コードが一度に複数のロックを保持する必要がある状況を特定し、コードベース全体に何らかの一般的な順序付けルールを課して、スレッドが複数の同時取得を実行できないようにすることです。順不同でロックします。たとえば、A
とB
を必要とするスレッドがB
を保持せずにA
を取得できない場合、上記のデッドロックに陥ることは不可能です。
低レベルでは、ミューテックスは2つのデータを含むと考えることができます。スレッドID番号(または現在ロック解除されている場合は0)などの現在のホルダーを識別する変数と、現在待機しているスレッドのある種のリストです。その上に。このデータへのアクセスは アトミック操作 によって制御され、ミューテックスを取得しようとする複数のスレッドが相互に上書きまたは破損しないようにします。