8

デッドロックを回避するための一般的なルールとして、 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
        }
    }
}

要約すると、同期/ロックのベスト プラクティスは次のようにする必要があることを理解しました。

  1. プライベート SyncRoot オブジェクトは、パブリック プロパティを通じて公開しないでください。つまり、カスタム データ構造はパブリックSyncRootプロパティを提供するべきではありません (このコメントも参照してください)。
  2. 一般に、ロックにプライベート オブジェクトを使用することは必須ではありません (この回答を参照してください)。
  3. クラスに複数の操作のセットがあり、相互に同期する必要はない場合は、複数のプライベート SyncRoot オブジェクトが必要です (このコメントを参照してください)。

上記はこのパターンの適切な使用法ですか?

4

2 に答える 2

4

SyncRoot私が設計する型にプロパティを追加することは避けたいと思います。理由は次のとおりです。

  • 私のタイプのユーザーは、別の同期メカニズムを使用する必要がある場合がありMutexますReaderWriterLockReaderWriterLockSlim

  • 型はより太くなります: その責任はより散らばります。明示的なマルチスレッド ロックのサポートを追加し、他の綿毛のサポートを追加しないのはなぜですか? 私はユーザーに 1 つの方法だけに従うように強制しますが、これはすべての場合に最適な解決策ではない可能性があります

  • プロパティを正しく実装する必要があります (またはを返さthisないtypeof(MyClass))。つまり、これは間違っています。

    public object SyncRoot {get {return this;}}
    

SyncRootまた、.NET フレームワーク型のプロパティを使用することも避けます。プロパティを持たない型をSyncRootスレッドセーフにする必要がある場合は、1 つのロック パターンを使用します。型にこのプロパティがある場合でも、ロック オンは選択しませんSyncRoot。これにより、コード スタイルが一貫し、読みやすく、維持しやすくなります。

于 2012-09-14T13:52:49.987 に答える
0

ここには多くの概念があります。まず、正しく実装したのは、クラスの消費者が独自の同期を行う必要のないスレッドセーフなクラスです。したがって、syncRoot オブジェクトを公開する必要はまったくありません。古い Collection クラスでは、クラスがスレッドセーフ ではないため、SyncRoot プロパティが公開されていました。

任意のオブジェクトをロックし、内部コレクションをロックしても、プログラムの正確さやパフォーマンスの点でまったく違いはありません。両方への参照が変更されない限り、これらは Monitor.Enter/Exit へのパラメーターと同様に機能します。あなたのインナーコレクションは変わりますか?いいえの場合は、読み取り専用としてマークします。

3 番目に、さまざまな操作に基づくさまざまなロックの使用に関するコメントがあります。この典型的な例は、ReaderWriterLock です。クラスによって公開されるさまざまな機能に基づいて、さまざまなレベルのロックを使用する必要性を分析する必要があります。

于 2012-09-14T13:33:31.747 に答える