C# にDictionary<K, V>
、複数のスレッドがアクセスして変更しているオブジェクトがあるとします。特定の操作をスレッドセーフにしたい。
したがって、ミューテックスに到達します。C# では、ミューテックスを使用する標準的な方法は次のとおりです。
lock (someSharedObject)
{
// Mutual exclusion zone here.
myDictionary.Add(1, "hello");
}
問題は、将来のプログラマーがミューテックスをバイパスして辞書に直接アクセスするのを防ぐために、単にドキュメントに依存していることです。
myDictionary.Add(1, "hello");
将来のプログラマが保護されていないディクショナリを使用できないようにするコンパイラが必要です。
2 つの一般的な可能性があります。
LockedDictionary
メンバー メソッドで確実にロックするが、他のすべての点で Dictionary のように機能する Dictionary に似たもの(たとえば、) を作成します。- へのアクセスをガードするクラスを作成して
Dictionary
、呼び出し元がDictionary
ガードを通過しないと に到達できないようにします。
これらは、少なくとも誤って、保護されていない辞書を誰も使用できないという望ましい特性を満たしています。両方の長所と短所について話し合い、私に同意するか反対するか、および私が見落としている可能性のある解決策を提案するようお願いします.
の利点はLockedDictionary
、他の人にとって直感的であることです。また、どのメソッドをどの程度ロックする必要があるかをきめ細かく制御できます。欠点は、正確にはDictionary
ではないため、このオブジェクトを を受け取ることを期待する関数に渡すことができないことですDictionary
。(ただし、実装することで近づけることができますIDictionary
。)
#2に進みます。ガード クラスの利点は、次のIDisposable
ように実装して使用できることです。
class DictionaryFortress {
Dictionary<K, V> realDict;
Object lockobject;
void Lock() {
Monitor.Enter(lockobject);
return DictionaryGuard(lockobject, realDict);
}
}
class DictionaryGuard : IDisposable {
public Dictionary<K, V> Dict {
get { return realDict; }
}
public void Dispose() {
Monitor.Exit(lockobject);
}
}
// in some class
DictionaryFortress dict = new DictionaryFortress(); // early on
// in a function, when we need to access dictionary contents...
using (DictionaryGuard guard = dict.Lock()) {
Dictionary<K, V> actualDict = guard.Dict;
// now you can pass actualDict anywhere; no one has to know that it's locked
}
もちろん、利点は、生のディクショナリにアクセスできることです。そのため、それを使用する方法や渡す場所に制限はありません。欠点は、それを使用するとオーバーヘッドが増えることです。また、利用可能なときにユーザーが参照を保存し、guard.Dict
DictionaryGuard が破棄された後にそれを使用することもできます。
私は#2に傾いています。長所と短所を見逃しましたか?悪用のリスクを最小限に抑えながら、辞書へのアクセスを保護するためのより良い方法はありますか? 繰り返しますが、私の要件は、物忘れや不注意なプログラマーがロック段階をスキップできないことです。私の望みは、慣用的で、便利で、柔軟であることです。