マルチスレッド アプリケーションに対して (いくつかの点で) 安全ではないオブジェクトがあり、重要なメソッドが同時にアクセスされないようにするための内部チェックを提供したいと考えています。
質問
複数のスレッドがクラスにアクセスすることを検出して防止するには、どのような手法を採用する必要がありますか?
消費者が使用するすべてのメソッド、プロパティなどで Thread.ID を追跡するだけで十分ですか?
マルチスレッド アプリケーションに対して (いくつかの点で) 安全ではないオブジェクトがあり、重要なメソッドが同時にアクセスされないようにするための内部チェックを提供したいと考えています。
質問
複数のスレッドがクラスにアクセスすることを検出して防止するには、どのような手法を採用する必要がありますか?
消費者が使用するすべてのメソッド、プロパティなどで Thread.ID を追跡するだけで十分ですか?
スレッドセーフではないことを文書化するだけです。これは、.NET のクラスで使用される規則です。
それは役に立ちますか?
lock(_padLock)
{
....
}
または、オブジェクトに外部からアクセスする場合は、Mutex オブジェクトを使用できます。
おそらく使用できる最良の内部チェックは、他のlock
人が提案したセットアップです。ただし、特定の問題を解決できるかどうかを調べるために、調査する価値のある創造的な方法をいくつか紹介します。私が抱えている問題は、クラスの一部だけが安全でないかどうか、クラスの異なるインスタンスを使用する異なるスレッドを持つことがスレッドセーフであるかどうかがわからないことです。したがってlock
、特定のシナリオを軽減するいくつかの組み合わせがあります
シナリオ 1: 静的クラス/メソッド - これにより、静的クラス/メンバーに誰がアクセスしても、別のスレッドが既にアクセスしている場合はブロックされます。
public static class UnsafeStaticClass
{
private static object _padLock = new object();
public static void UnsafeStaticMethod()
{
lock(_padLock)
{
// Do Work
}
}
}
シナリオ 2: インスタンスを並列にできる通常のクラスですが、インスタンスごとに 1 つの呼び出しのみが許可されます。複数のインスタンスがコード ブロックを同時に実行できます。
public class UnsafeClass
{
private object _padLock = new object();
public void UnsafeMethod()
{
lock(_padLock)
{
// Do Work
}
}
}
シナリオ 3: 安全でない静的メソッドと対話するクラス インスタンス - したがって、外側の静的メソッドへの呼び出しが 1 つだけ存在するようにする必要があります。インスタンスがいくつあっても、一度にメソッドを実行できるのはそのうちの 1 つだけです。これは、静的オブジェクトをロックしているためです。
public void UnsafeClass
{
private static object _padLock = new object();
public void UnsafeInstanceMethod()
{
lock(_padlock)
{
// Do Work
}
}
}
属性MethodImplOptionsには、Synchronizedの列挙型があります
メソッドを一度に1つのスレッドでのみ実行できることを指定します。静的メソッドは型をロックしますが、インスタンスメソッドはインスタンスをロックします。インスタンス関数のいずれかで実行できるスレッドは1つだけであり、クラスの静的関数のいずれかで実行できるスレッドは1つだけです。
...これはお勧めしませんが。このメソッドは、lock(this)
他のクラスによって誤ってまたは悪意を持ってロックが取得されることを可能にする機能と同等の機能を実行します
別のオプションは、ロックに使用される別のオブジェクトを使用することです。これを行うとき、Spinlockのような構造体でない限り、読み取り専用としてマークすることができます。つまり、Spinlockにreadonly属性を使用しないでください。これにより、SpinLockまたは_lock.Enterを呼び出すたびに、オブジェクトの新しいコピーを取得して成功します。これを行うと、破損する可能性があります。
class myClass
{
private object myLock; //OK
private readonly object myLock2; //OK
private readonly SpinLock myLock3; //WARNING: Value type, won't work as intended
private SpinLock myLock4; //OK
void DoStuff()
{
lock(myLock4)
{
// some quick instructions... say 10 or fewer
}
}
}
スレッド ID を確認すると、マルチスレッドの使用を検出できます。つまり、誰かがマルチスレッド プログラムでそれを使用すると、できればプログラムの使用を停止するメッセージが表示されます。エレガントではありませんが、最終的には人々にトラブルを警告します。プログラムがどのように使用されるかによって、人々がエラーに気付く前に深刻な被害が発生する可能性が決まります。
しかし、一般的に、シングルスレッド コードはマルチスレッド プログラムで非常にうまく機能します。高速で、(比較的)簡単に記述できます。(もちろん、呼び出しコードは非常に注意する必要があります。) クラスのこの機能を放棄し、最初から最後まで 1 つの単一スレッドで実行するように注意するプログラムでのみ実行するように制限することになります。プログラムの。たとえば、Windows デスクトップ プログラムでは、これはほとんどの場合、イベント キューで実行する必要があることを意味します。つまり、実行中は必然的にイベント キューを拘束することになります。つまり、ワーカー スレッドはありません!
ほとんどのコレクション クラスはシングルスレッドですが、マルチスレッド プログラムで広く使用されます。シングルスレッドコーディングのモデルとして使用します。