2011-01-06 5 views
6

이 확장 메서드는 스레드로부터 안전합니까?확장 메서드 스레드가 안전합니까?

public static class Extensions 
    { 
     public static void Raise<T>(this EventHandler<T> handler, 
     object sender, T args) where T : EventArgs 
     { 
     if (handler != null) handler(sender, args); 
     } 
    } 

또는이 값을 변경해야합니까?

public static class Extensions 
    { 
     public static void Raise<T>(this EventHandler<T> handler, 
     object sender, T args) where T : EventArgs 
     { 
     var h = handler; 
     if (h!= null) h(sender, args); 
     } 
    } 
+0

스레딩 관련 이벤트 디자인 및 구현 정보 http://stackoverflow.com/questions/786383/c-events-and-thread-safety – user44298

답변

9

흥미로운 루프 구멍을 발견하여 모두를 트랩했습니다. 아니요, 스레드로부터 안전하지 않습니다.

은 EventHandler <과 같은과 비슷하지만 참조는 메소드 인수를 통해 복사됩니다. 이는 런타임에 발생하지 않습니다. 확장 메서드는 일반 인스턴스 메서드와 마찬가지로 인라인 될 수 있습니다. 실제로, 그것은 매우 작기 때문에 극단적으로 인라인 될 가능성이 있습니다. 복사본이 없으므로 직접 만들어야합니다.

+1

나는 당신이 옳다고 생각하지 않습니다. 호출 함수가 다른 스레드 (예 : 로컬 변수 대신 클래스 필드)에 의해 수정 될 수있는 값에 대해 메서드를 호출 할 때만 적용됩니다. 나는 JIT가 그런 경우에 그런 전화를 인라인 할 것인지 모른다. – tster

+0

그러나 이것은 매우 흥미로운 주제입니다. 나는 직장에 없었 더라면 더 많은 것을 파고 들기를 바랬다. – tster

+1

글쎄, 그것은 이벤트 발생 코드의 null 테스트가 의미하는 것입니다. –

7

"threadsafe"의 의미에 따라 어느 버전도 threadsafe가 아닙니다. 두 번째 버전을 고려하십시오.

var h = handler;   
    if (h!= null) 
     h(sender, args); 

"handler"는 변경할 수없는 대리인이있는 일부 필드의 복사본입니다. null 체크 후에 다른 thread로 필드가 "null"에 변경되고 있다고합니다. 이 경우 원래의 null이 아닌 값의 복사본을 만들었 기 때문에 코드가 충돌하지 않습니다. 그러나 이 충돌하지 않으면 프로그램을 만들지 않습니다. 은 스레드 안전입니다. 충돌하지는 않지만 여전히 잘못된 결과를 생성하는 프로그램은 여전히 ​​스레드 안전하지 않습니다.

다른 스레드가 이벤트 필드를 null로 설정하면 이전 내용이 올바르게 실행되어야하는 일부 상태가 변경된 것으로 가정합니다. 이제 다른 스레드에서 방금 변형 된 상태에 따라 달라지는 이벤트 핸들러를 실행하려고합니다. 당신은 오래된 이벤트 핸들러를 실행 중입니다.

이 문제로부터 쉽게 보호 할 수있는 방법은 없습니다. 그것이 여러분이 처한 상황이라면 상황을 다루기 위해 매우 신중하게 스레딩 논리를 설계해야 할 것입니다.