2012-04-10 3 views
1

멀티 쓰레딩 시나리오에서 사용할 클래스에 목록이 있다고 가정 해 봅니다.스레드로부터 안전한 방법으로 목록 열거하기

public class MyClass 
{ 
    List<MyItem> _list= new List<MyItem>(); 
    protected object SyncRoot { 
     get { 
     return ((IList)_list).SyncRoot; 
     } 
    } 

    public void Execute1() 
    { 
     lock(SyncRoot) 
     { 
      foreach(var item in _list) DoSomething(item); 
     } 
    } 

    public void Execute2() 
    { 
     Item[] list; 
     lock(SyncRoot) 
     { 
      list=_list.ToArray(); 
     } 
      for(var i=0;i<list.Length;i++) DoSomething(list[i]); 
     } 
} 

있어서 Execute1 스레드 안전한 방식으로리스트를 열거 할 '정상'방법이다. 그러나 무엇에 관하여 Execute2? 이 방법은 여전히 ​​스레드로부터 안전한가요?

+1

아니요. MyItems가 참조 유형 (개체) 인 경우 Execute2가 안전하지 않습니다. 목록 및 배열은 모두 동일한 개체를 가리키고 있습니다. – Will

+0

@Will이 특정 시나리오에서는 문제가되지 않습니다. 목록 자체에 대해서만 염려합니다. 필요한 경우 개체가 자체적으로 동기화를 처리 할 수 ​​있습니다. – MikeSW

+0

@HenkHolterman 모든 개체를 사용할 수 있지만 목록의 동기화 개체를 사용하는 것이 더 나은지 궁금합니다. 내 말은 그게 노출 된 이유야. – MikeSW

답변

1

다른 모든 _list의 사용도 동일한 lock 문으로 보호되는 한 안전합니다. 목록에 대한 독점적 인 액세스 권한을 가지며 그 내용을 복사 한 다음 사본에 대한 작업을합니다 (범위 지정으로 인해 독점적으로 액세스 할 수 있음). 첫눈에 조금 낭비하지만 특정 상황에서는 합법적 인 접근법입니다.

+0

예, 목록에서 항목 추가/제거는 동일한 잠금을 사용하여 이루어집니다. 그러나 나는 왜 로컬리스트가 자동적으로 배타적 인 접근을 얻는 지 이해하지 못한다. – MikeSW

+0

@MikeSW : 메소드'Execute2'를 제외한 다른 모든 사람들에게는 범위를 벗어 났으므로. – Jon

2

(사본) 목록에 대한 액세스는 두 시나리오 모두에서 스레드 안전합니다. 물론 MyItem 요소는 어떤 방식으로도 동기화되지 않습니다.

두 번째 형식은 다소 비싸지 만 DoSomething()이 실행되는 동안 원본에 추가/제거 할 수 있습니다. 어레이가 일종의 스냅 샷처럼 작동합니다. 요구 사항이 충족되면 유용 할 수 있습니다. 참고로 ToList()을 사용할 수도 있습니다.

관련 문제