2009-12-09 4 views
5

우리는 사무실에서 약간의 토론을 가졌으며 문서화 된 답변을 얻지 못했습니다. 은 안전합니까?System.Array의 SetValue/GetValue 메서드는 스레드로부터 안전합니까?

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의 설명서를 살펴보십시오. 스레드 안전성에 관한 내용은 없습니다.

그것은에 존 소총의 대답에 의해 표현 된 것 같이 similar question :

내가 배열의 별도 부분에 각 스레드는 일 경우, 모두가 잘

I 될 것이라고 믿는다 이 문제와 관련하여 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 opcode가 생성되고 호출 opcode는 출력되지 않습니다. –

답변

3

MSDN (Visual Basic의 경우 Shared) Array class

공공 정적이 유형의 멤버는 스레드로부터 안전합니다. 모든 인스턴스 구성원은 스레드 안전성이 보장 된 이 아닙니다.

이 구현에서는 배열 에 대해 동기 (스레드 안전) 래퍼를 제공하지 않습니다. 그러나 .NET Framework 배열 기반 클래스는 속성을 사용하여 컬렉션의 컬렉션의 동기화 된 버전을 제공합니다.

스레드 안전하지 않습니다.

편집 : 배열은 IList의 인터페이스를 통해 사용하는 경우

몇 가지 추가 정보를 원하시면, Array 클래스의 메서드 SetValue은 정상적인 상황에서 호출되지 않습니다가, 그것은 단지라고.

다음 코드를

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

는 SetValue 매크로에 대한 호출을 (발생하지 않음), 대신 OpCodes.Stelem 연산 코드 대신 생성됩니다.

따라서 IList 참조를 사용하여 배열에 액세스하지 않으면 SetValue 메서드가 스레드로부터 안전한지 여부와 관계가 없습니다.

+0

나는 그것을 어떻게 놓쳤는 지 정말로 모른다. 감사! –

+1

일반적으로 스레드로부터 안전하지는 않지만 각 스레드가 배열의 개별 부분에만 액세스하는 특정 시나리오는 어떻습니까? –

+0

@divo, 스레드 안전성을 보장하지 않습니다. 즉, 현재 구현이 구현 세부 사항 인 경우에도 의미가 있습니다. –

0

각 스레드가 배열에 다른 항목을 설정하는 예제에서는 스레드로부터 안전합니다. 냉장고로 보아 거기에 맥주 캔 세 개가 있고 냉장고에 가서 맥주 한 캔을 골라 주면 모두 잘 갈 것이고 반쯤 마셔도 나중에 다시 돌려 놓을 것입니다. .

그러나 프로그래밍이나 실제 생활에서 맥주 1 캔을 3 인과 공유 할 수는 없습니다.

그래서 그래 : 각 스레드는 배열의 별도 부분에 작동하는 경우

, 모두 잘

PS 될 것입니다 : 그래도이를 확인하려면 어떤 소스를 가지고,하지만 일어날 항상 스레드를 사용하고 각 스레드가 배열에서 동시에 n 개의 쓰기를 읽을 때 기아 (?) 문제가 없었습니다. 나는 '맥주 한 캔'을 나눠 먹을 때 문제가 생기므로 내 대답은 정확하다고 믿지만, 누군가가 이것을 확인하고 싶습니다.

+0

어떻게 알 수 있습니까? 어쩌면'System.Array' 클래스가 모든 setter 호출마다 자체 캐시를 생성하고이 프로세스는 스레드로부터 안전하지 않을 수 있습니까? –

0

예에서 InternalSetValue(void *, object)에 대한 호출이 세 가지 다른 메모리 위치에 만들어집니다. 따라서 스레드로부터 안전해야합니다. 이러한 위치에 대한 쓰기는 동일한 배열의 구성원이더라도 다른 위치로 블리드되지 않습니다.

+0

실제로, 코드 예제는 나무가 다른 메모리 위치로 세 번'InternalSetValue'를 호출하지만, 그것은 내가 알 수있는 한도 내입니다. 나는 InternalSetValue의 구현이 무엇인지 알지 못한다. 따라서 스레드 안전성에 대해 확신 할 수 없다. –

관련 문제