何をどのようにロックするかは、何をしているかによって異なります。
たとえば、コーヒー メーカーなど、何らかのデバイスで作業しているとします。次のようなクラスがあるとします。
public CoffeeMaker {
private IntPtr _coffeeHandle;
private Object _lock = new Object();
}
この場合、_coffeeHandle (実際の物理デバイスへのポインター/ハンドル) へのアクセスを保護しているため、これは非常に簡単です。
public int AvailableCups {
get {
lock (_lock) {
return GetAvailableCups(_coffeeHandle); // P/Invoked
}
}
}
public void Dispense(int nCups)
{
lock (_lock) {
int nAvail = GetAvailableCups(_coffeeHandle);
if (nAvail < nCups) throw new CoffeeException("not enough coffee.");
Dispense(_coffeeHandle, nCups); // P/Invoked
}
}
そのため、マルチスレッド アプリを実行している場合、(おそらく) ディスペンス中に使用可能なカップ数を読み取りたくありません (ハードウェア エラーである可能性があります)。ハンドルへのアクセスを保護することで、それを保証できます。また、既に調剤しているのに調剤を求められることもありません。それは悪いことなので、それも保護されます。最後に、十分な量のコーヒーが利用可能で、それを確認するために公共の財産を使用していないことに気付いた場合を除き、私は分配しません。魔法の言葉はアトミックです。問題を発生させずに切り離すことはできません。
保護が必要なリソースのインスタンスが 1 つしかない場合は、静的オブジェクトをロックとして使用します。「シングルトンはありますか?」と考えてください。これは、静的ロックが必要になる場合のガイドラインになります。たとえば、CoffeeMaker にプライベート コンストラクターがあるとします。代わりに、コーヒー マシンを構築するファクトリ メソッドがあります。
static Object _factLock = new Object();
private CoffeeMaker(IntPtr handle) { _coffeeHandle = handle; }
public static CoffeeMaker GetCoffeeMaker()
{
lock (_factLock) {
IntPtr _handle = GetCoffeeMakerHandle(); // P/Invoked
if (_handle == IntPtr.Zero) return null;
return new CoffeeMaker(_handle);
}
}
この場合、CoffeeMaker はハンドルが処理されるようにIDisposable を実装する必要があるように感じます。
ただし、いくつかの問題があります。コーヒーが足りない場合は、もっと作る必要があるかもしれませんが、それには長い時間がかかります。コーヒーの調合には時間がかかるため、リソースの保護には細心の注意を払っています。ここで、このコーヒー メーカーに関するものはすべて独自のスレッドにすべきであり、コーヒーが飲み終わったときに発生するイベントが必要であると考えています。その後、複雑になり始め、知ることの重要性を理解しています。あなたがロックしているものと、いつコーヒーを作るのを妨げないようにします。
また、「デッドロック」、「アトミック」、「モニター」、「待機」、および「パルス」という言葉がすべてあなたにとってなじみのないものに聞こえる場合は、一般的なマルチプロセッシング/マルチスレッドについて読んで、公平な理髪店の問題を解決できるかどうかを確認する必要があります。問題または食事の哲学者の問題、どちらもリソース競合の典型的な例です。