2012-09-14 17 views
8

デッドロックを回避するための一般的なルールとして、SyncRootパターンについてお読みください。数年前の質問(link参照)を読んで、私はこのパターンのいくつかの使い方が間違っているかもしれないことを理解していると思います。特に、私はthis topicから以下の文章に焦点を当て:SyncRootパターンの説明:このパターンを使用する正しい方法は何ですか?

あなたがにSystem.Collectionsでのコレクションの多くのSyncRootのプロパティに気付くでしょう。私はこのプロパティが の間違いだったと思いますが、これらのコレクションの汎用バージョンを と同じように作成することはありません。

は実際には、例えば、List<T>クラスがSyncRootプロパティを実装していない、あるいはより正確には(this answerを参照)、明示的に実装されているので、あなたはそれを使用するためにICollectionにキャストしなければなりません。しかしthis commentは、プライベートSyncRootフィールドをパブリックにすることは、でも確認されているように、thisthis 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 
     } 
    } 
} 

は要約すると、私は次のように、同期/ロックするためのベストプラクティスがあるべきことを理解:

  1. どれ民間SyncRootのオブジェクトは、パブリックプロパティを介して公開すべきではありません。言い換えれば、カスタムデータ構造はpublic SyncRootプロパティを提供してはならない(this commentも参照)。
  2. 一般に、プライベートオブジェクトをロックに使用することは必須ではありません(this answer参照)。
  3. クラスに複数の同期操作を必要とするが、互いに同期させる必要がない場合は、複数のプライベートSyncRootオブジェクトが必要です(this commentを参照)。

このパターンの適切な使用の上に書かれているものは何ですか?

+0

私はクラスを内部的にスレッドセーフなものにしたいのであれば、内部的に(私的に)ロックを行い、クラスがスレッドセーフであることを文書化します。それ以外の場合は_no locking_を実行し、クラスがスレッドセーフではないことを文書化し、クラスのコンシューマに特定の用途に必要なときにロックを実装させます。 –

答えて

4

は理由があります:私のタイプの

  • ユーザーは、たとえばMutexのために、異なる同期メカニズムを使用する必要がある、またはReaderWriterLockまたはReaderWriterLockSlimあり

  • タイプが太くなります:その責任はより分散します。明示的なマルチスレッドロックのサポートを追加し、他の綿毛のサポートを追加しないのはなぜですか?私は、これは間違っている。すなわち、(何thisまたはtypeof(MyClass)を返す)私が正しくプロパティを実装する必要があるすべての場合

  • で最善の解決策になることはありませいない可能性がある、唯一の練習に従うことをユーザーに強制する:

    public object SyncRoot {get {return this;}} 
    

.NETフレームワークタイプのSyncRootプロパティも使用しないでください。型なしのタイプを作成する必要がある場合は、ロックパターンを1つ使用し、タイプにこのプロパティがある場合は、まだロックを選択しません。SyncRoot。これにより、私のコードスタイルは一貫性があり、読み込み/保守が容易になります。

0

ここにはいくつかの概念があります。まず、正しく実装したのは、クラスのコンシューマが自分の同期を行う必要がないスレッドセーフなクラスです。したがって、syncRootオブジェクトを公開する必要は全くありません。古いコレクションクラスでは、クラスがではなくスレッドセーフであるため、SyncRootプロパティが公開されました。

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

第3に、異なる操作に基づいて異なるロックの使用に関するコメントがあります。これの古典的な例はReaderWriterLockです。クラスによって公開されているさまざまな機能に基づいて、さまざまなレベルのロックを使用する必要性を分析する必要があります。私はここで、私はデザインの種類にSyncRootプロパティを追加しないでしょう