2010-01-08 3 views
4

나는 커스텀 이벤트 접근자를 만드는 방법에 대한 튜토리얼을 따라왔다. 이것은 내가 가지고있는 코드 :C# 내 잠금 선언문이 왜 매달 리지?

event ControlNameChangeHandler IProcessBlock.OnControlNameChanged 
{ 
    add 
    { 
     lock (ControlNameChanged) 
     { 
      ControlNameChanged += value; 
     } 
    } 
    remove 
    { 
     lock (ControlNameChanged) 
     { 
      ControlNameChanged -= value; 
     } 
    } 
} 

코드가 추가 statament에서 lock(ControlNameChanged)에 도달하는 순간 아무 일도 발생하지 않습니다. 코드가 더 이상 실행되지 않습니다. 그러나 내 응용 프로그램은 여전히 ​​작동 중입니다. 얼지 않아요.

무엇이 잘못 되었나요?

+1

핸들러를 실행하는 동안 핸들러를 변경하는 것은 정말 좋은 생각입니다! –

+0

당신은 어떻게 그걸 의미합니까? 미안 해요, 이거 처음이에요. – Martijn

+0

@Mitch : 명시 적 인터페이스 구현이므로 위임자 또는 동일한 객체의 다른 이벤트에 대한 참조와 비슷하게 보입니다. – Lucero

답변

13

아무튼, 다른 누군가가 자물쇠를 잡고 있습니다. 멀티 캐스트 대리인 인스턴스 또는 잠금 이벤트를 사용하면 안되며 공개 멤버도 사용하지 않아야합니다. 잠금을 설정할 사용자와 시간을 제어 할 수 없기 때문입니다.

그러므로 나는이 같은 별도의 잠금 객체를 사용하십시오 :

private readonly object controlNameChangedSync = new object(); 

event ControlNameChangeHandler IProcessBlock.OnControlNameChanged 
{ 
    add 
    { 
    lock (controlNameChangedSync) 
    { 
     ControlNameChanged += value; 
    } 
    } 
    remove 
    { 
    lock (controlNameChangedSync) 
    { 
     ControlNameChanged -= value; 
    } 
    } 
} 

참고 : 대리자에 += 또는 -=을 수행 할 때 이벤트에 대한 참조가 변경.

+0

참으로 (내 지금 삭제 된 답변은 똑같은 것을 말합니다). 현재 코드는 스레드로부터 안전하지 않습니다. –

+0

추가/제거를 생략 할 경우 암시 된 잠금이 아닙니까? 추가/제거에 대해 아무 것도 할 필요가 없다면 C#이 잠금을 수행하도록하십시오. 당신의 'lockchoice'기사에 추가/제거가 항상 포함 된 wrting 이벤트가 권장되지만 그 이유는 밝히지 않았다. –

+0

@Lucero : 나는 그것을 얻지 못한다. 왜 자물쇠를 사용해야합니까? 잠금 문을 주석으로 처리하면 모든 것이 잘 작동합니다. 솔루션에 대한 배경 정보를 제공 할 수 있습니까? – Martijn

4

+=-= 연산자 변경 대리인. 그래서 당신의 Add와 Remove 메쏘드는 매번 다른 객체들에 대해 잠그고 있고, 당신은 전혀 동기화가 없습니다.

이제 차단에 대해 설명하지는 않지만 실제 발생 상황에 대한 귀하의 질문은 명확하지 않습니다. 나는이 프로그램이 경쟁 조건의 가능성으로 '정상적으로'실행될 것으로 기대한다.

8

코드는 객체를 종료는 사용자가 입력 한 것과 다른 것을

event ControlNameChangeHandler IProcessBlock.OnControlNameChanged { 
    add { 
     try { 
      Monitor.Enter(ControlNameChanged); 
      ControlNameChanged = ControlNameChanged + value; 
     } 
     finally { 
      Monitor.Exit(ControlNameChanged); 
     } 
    } 
    remove { 
     try { 
      Monitor.Enter(ControlNameChanged); 
      ControlNameChanged = ControlNameChanged - value; 
     } 
     finally { 
      Monitor.Exit(ControlNameChanged); 
     } 
    } 
} 

주에 해당합니다. 즉, 결코 풀리지 않는 하나의 자물쇠를 가져 왔으며 하나의 자물쇠는 풀리지 만 결코 잡히지 않습니다. 코드를 다음과 같이 변경해야합니다 :

private object padlock = new object(); 
event ControlNameChangeHandler IProcessBlock.OnControlNameChanged { 
    add { 
     lock (padlock) { 
      ControlNameChanged += value; 
     } 
    } 
    remove { 
     lock (padlock) { 
      ControlNameChanged -= value; 
     } 
    } 
} 
+0

위대한 설명! 귀하의 게시물을 읽을 때까지 완전히 이해하지 못했습니다. – leiflundgren