デッドロックを回避するための一般的なルールとして、SyncRootパターンについてお読みください。数年前の質問(link参照)を読んで、私はこのパターンのいくつかの使い方が間違っているかもしれないことを理解していると思います。特に、私はthis topicから以下の文章に焦点を当て:SyncRootパターンの説明:このパターンを使用する正しい方法は何ですか?
あなたがにSystem.Collectionsでのコレクションの多くのSyncRootのプロパティに気付くでしょう。私はこのプロパティが の間違いだったと思いますが、これらのコレクションの汎用バージョンを と同じように作成することはありません。
は実際には、例えば、List<T>
クラスがSyncRoot
プロパティを実装していない、あるいはより正確には(this answerを参照)、明示的に実装されているので、あなたはそれを使用するためにICollection
にキャストしなければなりません。しかしthis commentは、プライベートSyncRoot
フィールドをパブリックにすることは、でも確認されているように、this
(this answerを参照)でロックするのと同じように悪い習慣であると主張しています。
したがって、スレッドセーフではないデータ構造を実装すると、マルチスレッドのコンテキストで使用できるので、実際には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のオブジェクトは、パブリックプロパティを介して公開すべきではありません。言い換えれば、カスタムデータ構造はpublic
SyncRoot
プロパティを提供してはならない(this commentも参照)。 - 一般に、プライベートオブジェクトをロックに使用することは必須ではありません(this answer参照)。
- クラスに複数の同期操作を必要とするが、互いに同期させる必要がない場合は、複数のプライベートSyncRootオブジェクトが必要です(this commentを参照)。
このパターンの適切な使用の上に書かれているものは何ですか?
私はクラスを内部的にスレッドセーフなものにしたいのであれば、内部的に(私的に)ロックを行い、クラスがスレッドセーフであることを文書化します。それ以外の場合は_no locking_を実行し、クラスがスレッドセーフではないことを文書化し、クラスのコンシューマに特定の用途に必要なときにロックを実装させます。 –