2011-07-24 52 views
4

基本的に私は3つの異なるスレッドを呼び出すアプリケーションを持っていますが、それぞれ新しいHashSetと私が知りたいのはこのスレッドセーフですか?または各ハッシュセットに[ThreadStatic]を追加する必要がありますか?public static HashSet <string>スレッドセーフですか?

答えて

6

3つの異なるHashSetをインスタンス化し、それぞれのHashSetにアクセスする場合は、1つのスレッドでしかアクセスできません。スレッド内で共有される1つのスタティックHashSetがある場合は、[ThreadStatic]属性を追加する必要があります。

[更新][ThreadStatic]がどのように機能するかを明確にするだけです。

免責事項:I 決してを使用[ThreadStatic]。その属性の存在は明白ではなく、(適切にテストするだけでなく)デバッグするのが難しい多くの結果をもたらします。

のは、あなたが本当にテストクラスで[ThreadStatic]を使用したいとしましょう:次のコンソールアプリ実行

public class ThreadStaticTest 
{ 
    // CLR ensures that each thread accessing this field 
    // gets a separate instance of the *field*. This, however, 
    // means that static initializers don't work. Field is 
    // null at first access from an individual thread 
    [ThreadStatic] 
    static HashSet<string> _hashset; 

    // This is why we instantiate it explicitly here: 
    private HashSet<string> HashSet 
    { 
     get 
     { 
      _hashset = _hashset ?? new HashSet<string>(); 
      return _hashset; 
     } 
    } 

    public void AddItem(string s) 
    { 
     // thread safe 
     HashSet.Add(s); 
    } 

    public IEnumerable<string> GetItems() 
    { 
     // thread safe 
     return HashSet; 
    } 
} 

static void Main(string[] args) 
{ 
    // single test instance! 
    var test = new ThreadStaticTest(); 

    List<Thread> threads = new List<Thread>(); 
    for (int i = 0; i < 5; i++) 
    { 
     threads.Add(new Thread(() => 
     { 
      var threadId = Thread.CurrentThread.ManagedThreadId; 
      test.AddItem("Hello from thread #" + threadId); 
      Console.WriteLine("Instance contains {0} items: '{1}'", 
       test.GetItems().Count(), 
       string.Join(", ", test.GetItems().ToArray())); 
     })); 
    } 
    threads.ForEach(t => t.Start()); 
    threads.ForEach(t => t.Join()); 

    Console.Read(); 
} 

は、各スレッド、単一のテストインスタンスがあるが、ことを示しますハッシュセットの新しいインスタンスを取得します。

 
Instance contains 1 items: 'Hello from thread #11' 
Instance contains 1 items: 'Hello from thread #13' 
Instance contains 1 items: 'Hello from thread #10' 
Instance contains 1 items: 'Hello from thread #12' 
Instance contains 1 items: 'Hello from thread #14' 
+1

これは正しくはありません。 "静的フィールドの値がスレッドごとに一意であることを示します。"したがって、スレッド間でデータの共有はできません。すなわち3つのスレッド== 3つの静的インスタンス。 – sgtz

+1

@sgtzが正しいです。 '[ThreadStatic]'はHashSetを魔法のようにスレッドセーフにしません。静的フィールドにアクセスするスレッドごとに異なる格納場所を表示します。 @Mike:あなた自身で 'HashSet'へのアクセスを同期させるか、' ConcurrentDictionary'のようなフリースレッドのコレクションを使う必要があります。 –

+0

@sgtz:「スレッド間でデータの共有はできません」という意味はわかりません。 2つの場合ではありません。1.スレッドごとに1つの**インスタンス**がある場合、または** [ThreadStatic]で**静的**フィールドマークがある場合。私はあなたが間違っていると信じている部分を理解していません。 @Allon:OPは、1つのHashSetをスレッドセーフな「魔法のような」ものにしたくない場合、別のスレッドでアクセスされる3つの別々のHashSetが '[ThreadStatic]'でマークされる必要があるかどうか尋ねました。 HashSetがすべてのスレッドから同時にアクセス可能な静的フィールドでない限り、答えは** no **です(そうではありません)。 – Groo

4

MSDNドキュメントHashSet

この型のパブリックstatic(Visual BasicではShared)のメンバーはすべて、スレッドセーフです。どのインスタンスメンバーもスレッドセーフであるとは限りません。

関連する問題