デッドロックを回避するための一般的なルールとして、 SyncRoot パターンについて何かを読みました。そして、数年前の質問 (このリンクを参照) を読んで、このパターンの一部の使用が正しくない可能性があることを理解していると思います。特に、このトピックの次の文に注目しました。
System.Collections のコレクションの多くに SyncRoot プロパティがあることに気付くでしょう。振り返ってみると、このプロパティは間違いだったと思います...これらのコレクションの汎用バージョンを構築するときに同じ間違いを犯すことはありませんのでご安心ください。
実際、たとえば、List<T>
クラスはプロパティを実装していないSyncRoot
か、より正確には明示的に実装されているため (この回答を参照)、それを使用するにはキャストする必要がありますICollection
。しかし、このコメントでは、このコメントでも確認されているように、プライベートSyncRoot
フィールドをパブリックにすることはロックオンと同じくらい悪い習慣であると主張していthis
ます (この回答を参照) 。
したがって、私が正しく理解していれば、非スレッドセーフなデータ構造を実装する場合、それはマルチスレッド コンテキストで使用できるため、SyncRoot
プロパティを提供するべきではありません (実際にはすべきではありません)。ただし、次のサンプル コードのように、このデータ構造をプライベート SyncRoot オブジェクトに関連付ける作業は、開発者 (このデータ構造を使用する開発者) に任せる必要があります。
public class A
{
private MyNonThreadSafeDataStructure list;
private readonly object list_SyncRoot = new object;
public Method1()
{
lock(list_SyncRoot)
{
// access to "list" private field
}
}
public Method2()
{
lock(list_SyncRoot)
{
// access to "list" private field
}
}
}
要約すると、同期/ロックのベスト プラクティスは次のようにする必要があることを理解しました。
- プライベート SyncRoot オブジェクトは、パブリック プロパティを通じて公開しないでください。つまり、カスタム データ構造はパブリック
SyncRoot
プロパティを提供するべきではありません (このコメントも参照してください)。 - 一般に、ロックにプライベート オブジェクトを使用することは必須ではありません (この回答を参照してください)。
- クラスに複数の操作のセットがあり、相互に同期する必要はない場合は、複数のプライベート SyncRoot オブジェクトが必要です (このコメントを参照してください)。
上記はこのパターンの適切な使用法ですか?