2009-12-09 13 views
5

私たちはオフィスで少し議論しましたが、文書化された答えはありませんでした。System.ArrayのSetValue/GetValueメソッドはスレッドセーフですか?

System.Array.SetValueはスレッドセーフですか?

using System; 
using System.Text; 
using System.Threading; 

namespace MyApp 
{ 
    class Program 
    { 
     private static readonly object[] arr = new object[3]; 

     static void Main(string[] args) 
     { 
      string value1 = "hello"; 
      int value2 = 123; 
      StringBuilder value3 = new StringBuilder(); 
      value3.Append("this"); 
      value3.Append(" is "); 
      value3.Append("from the StringBuilder"); 

      var states = new object[] 
          { 
           new object[] {0, value1}, 
           new object[] {1, value2}, 
           new object[] {2, value3} 
          }; 

      ThreadPool.QueueUserWorkItem(MySetValue, states[0]); 
      ThreadPool.QueueUserWorkItem(MySetValue, states[1]); 
      ThreadPool.QueueUserWorkItem(MySetValue, states[2]); 
      Thread.Sleep(0); 

      Console.WriteLine("press enter to continue"); 
      Console.ReadLine(); 

      // print the result 
      Console.WriteLine("result:"); 
      for (int i = 0; i < arr.Length; i++) 
      { 
       Console.WriteLine("arr[{0}] = {1}", i, arr[i]); 
      } 

      // quit 
      Console.WriteLine("press enter to quit"); 
      Console.ReadLine(); 

     } 

     // callback 
     private static void MySetValue(object state) 
     { 
      var args = (object[]) state; 
      var index = (int)args[0]; 
      var value = args[1]; 
      arr[index] = value; // THREAD-SAFE ?? 
     } 
    } 
} 

ご覧のとおり、すべてのスレッドは、静的配列に異なる固有の項目を設定します。私はリフレクターを使ってコードを深く見ていました(そして、mscorlib.pdbを調べました)。最終的には

[MethodImplAttribute(MethodImplOptions.InternalCall)] 
private unsafe extern static void InternalSetValue(void * target, Object value); 

への電話があります。これは文書化されていません。一般にSystem.Array、特にSetValue(object, int)へのMSDNのドキュメントを見てください。スレッドセーフについては何もありません。私は、配列の別の部分に、各スレッドが唯一の 作品ならば、 すべてがうまく

Iになると信じてい

:それはsimilar questionにジョンスキートの答えによって表現だとして

この問題に関してはGetValue(int)SetValue(object, int)に明確な回答を得ようとしています。誰かが文書のリンクを持っていますか、またはInternalSetValueのより良い理解を持っていますか?

+0

Eric Lippertが実際に意味する「スレッドセーフ」については、よくお読みください。http://blogs.msdn.com/ericlippert/archive/2009/10/19/what-is-this-thing-you-call -thread-safe.aspx –

+0

あなたの例では、SetValueメソッドは呼び出されず、代わりにStelemオペコードがコールオペコードではなくコンパイラによって生成されます。 –

答えて

3

MSDN:Array class

(Visual BasicではShared)この型のpublic static メンバーは、スレッドセーフです。 すべてのインスタンスメンバーは、スレッドセーフであることが保証されている ではありません。

この実装では、配列 の同期(スレッドセーフ)ラッパーは提供されません。ただし、.NET Framework クラスは、SyncRoot プロパティを使用して 独自の同期バージョンの コレクションを提供します。

スレッドセーフではありません。

編集:

いくつかの余分な情報、ArrayクラスのメソッドSetValueは、通常の状況で呼び出されていない配列は、IListインターフェイスを介して使用されている場合、それが唯一と呼ばれています。

次のコード:

int[] arr = ... 
arr[i] = value; 

はのSetValue(への呼び出しを生成しません)、代わりにOpCodes.Stelemオペコードが代わりに生成されます。

したがって、IList参照を使用して配列にアクセスしない限り、SetValueメソッドがスレッドセーフであるかどうかは関係ありません。

+0

私は本当にそれを逃した方法を知りません。ありがとう! –

+1

一般にスレッドセーフではありませんが、個々のスレッドがアレイの別々の部分にしかアクセスしない特定のシナリオはどうですか? –

+0

@divo、スレッドセーフであることが保証されていません。つまり、現在の実装が実装の詳細であっても意味します。 –

0

各スレッドが配列内の別のアイテムを設定する例では、スレッドセーフになります。 冷蔵庫として見て、そこには3缶のビールがあり、3っは冷蔵庫に行き、ビールの缶を選ぶと、すべてがうまく行きます、彼らはそれを半分飲むでしょう、それを後で戻して戻します。

しかし、プログラミングや実生活ではビール1缶を3人で共有することはできません。

はそうそう:各スレッドが唯一の配列の別の部分に動作するかどう

、すべてがうまく

PSになります:私はこれを確認するには、noソースを持っていないが、それに起こります常にスレッドを使用していて、各スレッドが同時にn個の書き込みをアレイで読み取るときに、飢餓状態(?)の問題は発生しませんでした。私は「同じビールの缶」を共有するときに問題を抱えているので、私の答えは正しいと信じていますが、誰かがこれを確認したいと思っています。

+0

どのように伝えることができますか?たぶん 'System.Array'クラスはすべてのsetter呼び出しで独自のキャッシュを生成しますが、このプロセスはスレッドセーフではありませんか? –

0

例では、InternalSetValue(void *, object)への呼び出しが3つの異なるメモリ位置に行われています。したがって、スレッドセーフである必要があります。それらの場所への書き込みは、同じ配列のメンバであっても、他の場所に書き込まれることはありません。

+0

実際、このコード例では、ツリーの異なるメモリ位置で3回「InternalSetValue」を呼び出していますが、それは私が知る限りです。私は 'InternalSetValue'の実装が何であるかわからないので、スレッドの安全性についてはわかりません。 –

関連する問題