2010-01-22 6 views
2

나는 몇 가지 데이터 멤버와 클래스가 있습니다. 나는 Foo 클래스도 안전하게 쓰레드로 만들고 싶습니다. 아래 코드가이 작업을 수행하는 가장 좋은 방법입니까?C# 중첩는 동기화

public Foo(Foo f) 
{ 
    lock(f) 
    { 
     foreach (int i in f.intLst) 
     { 
      this.intLst.Add(i) 
     } 
     //More complicated 
    } 
} 

public Foo Merge(Foo f1, Foo f2) 
{ 
    Foo fReturn = new Foo(f1);//Using the constructor above 

    lock(f2) 
    { 
     foreach (int i in f2.intLst) 
     { 
      fReturn.intLst.Add(i); 
     } 

     //More complicated merge code 
    } 

    return fReturn; 
} 

간단합니까? 대신 모니터를 사용해야합니까? 나는 락이 모니터 클래스를 구현한다는 것을 알고 있지만 아마도 여전히 이유가있다. 또한 위 샘플에서 교착 상태 처리에 대해 걱정할 필요가 있습니다.

f1에 복사 생성자 중에 f2가 변경되면 f1과 f2를 모두 lock()해야 할 필요가 있습니다.

+0

목록에 유형에는 Union() 및 Concat() 메소드가 있습니다. –

답변

2

예, 간단합니다.

코드가 좋습니다. 액세스 할 때까지 f2를 잠글 필요가 없으며 f1을 복사 한 후에 f1을 잠그지 않아도됩니다. 그래서 동시에 둘 다 잠글 필요가 없습니다.

예를 들어 항목 자체는 변경할 수없는 단순한 정수이므로 잠글 필요가 없지만 변경할 수있는 항목이있는 경우 개별 항목을 잠글 필요가 있습니다.

한 번에 하나의 잠금 만 있기 때문에이 코드로 교착 상태가 걱정되지 않아도됩니다. 물론 다른 코드가 잠금을 유지하면서 호출하면 교착 상태의 가능성에 대해 걱정할 필요가 있습니다.

+0

실제 응용 프로그램에서는 항목을 변경할 수 있습니다. Merge()에서 복사 생성자를 호출하면 잠기기 전에 f2가 변경 될 수 있다고 생각합니까? 이 올바른지. Merge 함수가 호출되면 f1과 f2를 모두 변경할 수 없도록하고 싶습니다. 나는 약간의 안심이 필요할지도 모른다. – Ames

+0

고려해야 할 시나리오는 다음과 같습니다. 1. 코드 복사본 f1이 잠금을 해제합니다. 2. 다른 스레드가 f1과 f2를 모두 변경합니다. 3. 코드 사본 f2가 잠금을 해제합니다. 이 시나리오에서 코드에는 다른 스레드가 변경되기 전의 f1 사본과 이후부터 f2 사본이 있습니다. 귀하의 특정 응용 프로그램에서 이것은 나쁜 일이 될 수 있습니까? 대답이 '예'인 경우 추가 잠금이 필요합니다. 대답이 '아니오'라면, 그렇지 않습니다. 일반적으로이 두 가지가 모두 단일 구조의 일부일 경우 대답은 '예'가됩니다.이 경우 구조를 잠 가야합니다. –

+0

설명 주셔서 감사합니다. – Ames

0

lock()은 다른 lock() 블록에서만 작동합니다. 따라서 lock (f)는 lock (f)을 가지고있는 한 f로 작업중인 다른 코드를 차단하므로 lock (f)은 (f)의 모든 용도에 적용되어야합니다.

대상 Foo가 아직 구성되지 않았으므로 걱정할 필요가 없습니다. 다른 사람은 아직 참조 할 수 없습니다.