2009-04-10 5 views
10

제 생각에 C#의 일반 목록 (목록)을 사용하는 경우 여러 동시 판독기를 지원할 수 있지만 하나의 작성기 만 지원할 수 있습니다. 또한 작성자를 믹스에 도입 할 때 작업을 스레드로부터 안전하게 유지하기 위해 동기화 구문을 제공해야합니다.Is <T> .Contains() 스레드 안전 호출 - C#

List.Contains가 읽기 작업으로 간주됩니까? 즉,이 메서드를 호출하면 작성자가 동시에이 목록에 쓸 수 있다고 걱정할 필요가 있습니까?

+0

어떻게 작동하는지 생각해보십시오. List .Remove() 호출이 동시에 이루어지면 배열 경계 바깥의 값을 쉽게 확인할 수있는 for 루프 (또는 정렬 된 목록 인 경우 다른 것)가 가장 많이 사용됩니다. "배열 인덱스가 범위를 벗어났습니다." 예외가 throw됩니다. –

답변

23

예. 그렇습니다. 기본적으로 나는 목록이 동시에 쓰기 위해 사용될 수 있다면 작업을 위해 동기화 할 것입니다.

일반적으로 모음은 두 가지 범주로 나뉩니다. 하나는 생성되고 초기화 된 다음 다시 변경되지 않으며 스레드로부터 안전하며 시간이 지남에 따라 변형됩니다 (스레드 액세스가 아닌 모든 액세스에 대해 잠금).

+5

하나를 인스턴스화하고 채우고 다시 사용하지 않는 경우 ReadOnlyCollection ()에 랩핑하면 도움이됩니다. 소비자가 컬렉션의 기본 항목을 변경하는 것을 중지하지 않지만 원래 목록에 대한 참조를 버리면 반복이 안전합니다. –

+0

Scott : 합의했습니다 - 그것이 훨씬 명확 해집니다. 개인적으로 필자는 필요하다면 빌더 유형을 사용하여 건설 직후 불변성을 보장하는 콜렉션 유형을 사용하지만 핵심 프레임 워크에서는 사용할 수 없습니다. ( –

2

List<T>.Contains은 확실히 읽기 작업입니다. 다른 스레드가 그것을 읽을 때 콜렉션에 쓰는 것이 가능할 수 있습니다. 컬렉션을, 열거 doc에 따르면

+0

그리고 Contains가 실행되는 동안 컬렉션이 변경되면 어떻게됩니까? –

+0

이제는 좋지 않음 –

1

...

이 프로시 저는 기본적으로 스레드로부터 안전하지 않습니다.

따라서 스레드로부터 안전하지 않다고 말할 수 있습니다. 잠 가야합니다.

0

작성자가 동시에 작성하는 경우 List.Contains는 확실히 스레드로부터 안전하지 않습니다. 그것을 자물쇠로 감싸고 자물쇠를 채워야합니다.

2

예, 걱정해야합니다! List.Contains는 EqualityComparer를 가져 와서 목록에 매개 변수로 전달 된 항목을 현재 반복의 인덱스에있는 항목과 비교하는 모든 항목을 반복하므로 목록이 반복되는 동안 수정되면 결과가 예측할 수 없게됩니다.

1

이것은 스레드 세이프 작업이 아닌 것으로 간주하는 것이 안전합니다. MSDN description 그것을 요약 :

가 ...이 방법은 항목 이 있는지 여부를 확인하기 위해 컬렉션의 개체의 같음과 항목 은 compareTo 메소드를 사용합니다.

따라서 읽기 작업 후 비교 작업입니다.

1

다중 스레드 환경에서 동시에 컬렉션에 쓰기가 없는지 확인해야합니다. 여기 반영 자의 코드가 있습니다. 컬렉션 자체가 자물쇠를 제공하지 않았으므로 원산지입니다.

public bool Contains(T item) 
{ 
    if (item == null) 
    { 
     for (int j = 0; j < this._size; j++) 
     { 
      if (this._items[j] == null) 
      { 
       return true; 
      } 
     } 
     return false; 
    } 
    EqualityComparer<T> comparer = EqualityComparer<T>.Default; 
    for (int i = 0; i < this._size; i++) 
    { 
     if (comparer.Equals(this._items[i], item)) 
     { 
      return true; 
     } 
    } 
    return false; 
} 
+0

+1 생각하는 위대한 마음을 위해서 +1 –

0

읽기 작업으로 간주됩니다. 어떤 경기 조건에도 부딪치지 않지만 최신 정보를 얻으려는 경우 Listvolatile을 만들 수 있습니다. the MSDN documentation에 따르면

0

:

공공 정적이 유형의 (Visual Basic의 경우 Shared) 멤버는 스레드로부터 안전합니다.모든 인스턴스 멤버가 스레드로부터 안전하다는 보장은 없습니다.

ReaderWriterLock 클래스는 찾고있는 동기화 용으로 제작 된 것 같습니다. 당신이 볼 수 있듯이

public bool Contains(T item) 
    { 
     if (item == null) 
     { 
      for (int j = 0; j < this._size; j++) 
      { 
       if (this._items[j] == null) 
       { 
        return true; 
       } 
      } 
      return false; 
     } 
     EqualityComparer<T> comparer = EqualityComparer<T>.Default; 
     for (int i = 0; i < this._size; i++) 
     { 
      if (comparer.Equals(this._items[i], item)) 
      { 
       return true; 
      } 
     } 
     return false; 
    } 

, 그것은 확실히 '읽기'작업입니다 항목을 통해 단순한 반복이다 : 당신이 코드를 검사 리플렉터를 사용하는 경우

4

, 당신이 뭔가를 얻을. 읽기 전용으로 만 사용할 경우 (아무 것도 항목을 변경하지 않음) 잠글 필요가 없습니다. 별도의 스레드에서 목록을 수정하기 시작하면 가장 확실하게 액세스를 동기화해야합니다.

+0

그것은 틀린 것 같습니다. _size 변수와 내부 배열의 인덱스에 계속 영향을 미치고있는 읽기 작업입니다. 이들은 바운드 예외 예외가 발생한 곳과 정확히 같습니다. @JonSkeet? –