2009-04-27 5 views
2

이 ValueStore 클래스는 스레드 안전합니까? GetInt (문자열 키)의 잠금 범위가 수익률 반환을 중심으로 확장되어야합니까?이 클래스는 스레드 안전합니까?

public class ValueStore 
{ 
    private readonly object _locker = new object(); 
    private readonly Dictionary<string, int> _data = 
    new Dictionary<string, int>(); 

    public ValueStore(Dictionary<string, int> data) 
    { 
    _data = data; 
    } 

    public IEnumerable<int> GetInt(string key) 
    { 
    IEnumerable<KeyValuePair<string, int>> selected; 
    lock(_locker) 
    { 
     selected = _data.Where(x => x.Key.Equals(key)); 
    } 

    foreach (KeyValuePair<string, int> pair in selected) 
    { 
     yield return pair.Value; 
    } 
    } 
} 

단위 테스트는 잘 될 것 같다 :

[TestFixture] 
public class ValueStoreTest 
{ 
    [Test] 
    public void test1() 
    { 
    Dictionary<string, int> data = new Dictionary<string, int>(); 
    for (int i = 0; i < 100000; i++) 
    { 
     data.Add(i.ToString(),i); 
    } 

    ValueStore vs = new ValueStore(data); 

    for (int i = 0; i < 900000; i++) 
    { 
     ThreadPool.QueueUserWorkItem(delegate 
     { 
     for (int j = 0; j < 100000; j++) 
     { 
      IEnumerable<int> d = vs.GetInt(j.ToString()); 
     } 
     }); 
    } 
    } 
} 
+0

스레드 안전보다 심각한 문제가 있습니다. 사전을 잘못 사용하고 있습니다. 목록처럼 사용하고 있습니다. - 키에 여러 값을 할당 할 수 있다고 생각하는 것 같습니다. 당신은 할 수 없습니다. 따라서 생산량은 불필요합니다. - contains/get 메서드를 사용하는 대신 사전의 모든 값을 열거합니다. –

답변

6

아니, 확실히 스레드 안전 아닙니다.

클라이언트가 전달한 사전을 사용한다는 사실은 클라이언트가 클라이언트를 변경할 때를 제어 할 수 없다는 것을 의미합니다. Where 절을 적용 할 때만 잠글 수도 있지만 실제로 반복을 수행하지는 않습니다. 결과를 반복하는 동안 잠금을 유지해야하지만 이전에 말했듯이 클라이언트가 언제든지 사전을 변경하지 못하도록 막지는 않습니다.

클래스에서 사전을 생성하고 그 안에 데이터 만 노출 한 경우 (즉, 외부 세계로부터 보호 된 경우) 완전히 스레드로부터 안전하게 보호 할 수 있습니다. 클라이언트 코드가 사전을 변경하지 않는다고 주장하면 사전이 작성자가 없을 때 여러 스레드에서 읽는 것이 안전하므로 잠금이 필요하지 않습니다.

1

자물쇠에있는 문은 잠금이 해제 될 때까지 실행되지 않는다고 말할 수 있습니다. 반복 도중 컬렉션을 잠그면 yield 문을 lock 문으로 이동해야합니다.

+2

잠금 *의 문이 잠금에서 실행됩니다. 이 명령문은 지연 실행 반복자를 반환합니다. * lambda 표현식 *은 자물쇠에서 실행되지 않습니다. –

1

아니요, 아닙니다. 생성자로 전달한 Dictionary<string, int> 객체에 대한 읽기 및 쓰기를 시작하면 문제가 발생합니다. _data의 클래스 선언은 생성자의 할당에 즉시 덮어 씁니다.

이 문제를 해결하려면 생성자의 Dictionary에서 전달 된 각 키/값 쌍을 직접 할당 대신 클래스 Dictionary으로 복사하십시오.

그렇다면 스레드 안전하다고 생각하지만 분명히 클래스는 읽기 전용입니다.

관련 문제