당신이 지적으로, 어디에 여러 스레드가 동시에 SomeEvent
에 액세스 할 수 있습니다, 하나 개의 스레드는 SomeEvent
가 null 여부를 확인하고 있음을 확인할 수 있었다 그렇지 않습니다. 이렇게하면 다른 스레드가 마지막으로 등록한 대리자를 SomeEvent
에서 제거 할 수 있습니다. 첫 번째 스레드가 SomeEvent
을 발생 시키려고하면 예외가 발생합니다. 이 시나리오를 피하기 위해 합리적인 방법은 다음과 같습니다
이 대리자의하는 Delegate.Combine 및 Delegate.Remove 정적 접근을 추가의 기본 구현을 사용하여 제거 이벤트에서 추가 또는 제거 할 때마다 때문에 작동
protected virtual void OnSomeEvent(EventArgs args)
{
EventHandler ev = SomeEvent;
if (ev != null) ev(this, args);
}
방법이 사용됩니다. 이러한 각 메서드는 전달 된 대리자를 수정하는 대신 대리인의 새 인스턴스를 반환합니다.
또한 .NET에서 개체 참조를 할당하는 작업은 atomic이고 추가 및 제거 이벤트 접근 자의 기본 구현은 synchronised입니다. 위의 코드는 먼저 멀티 캐스트 대리자를 이벤트에서 임시 변수로 복사하여 성공합니다. 이 시점 이후에 SomeEvent를 변경해도 사용자가 작성하여 저장 한 사본에는 영향을 미치지 않습니다. 따라서 이제는 모든 대리자가 등록되었고 이후에 호출 될 수 있는지 여부를 안전하게 테스트 할 수 있습니다. 이 솔루션이 호출 할 때, 즉 그 이벤트 핸들러가 null 인, 하나의 인종 문제를 해결하는 것이
참고. 이벤트 핸들러가 호출 될 때 이벤트 처리기가 작동하지 않거나 복사가 수행 된 후에 이벤트 핸들러가 등록하는 문제는 처리하지 않습니다. 이벤트 핸들러는 즉시 핸들러가 해제 가입되어 파괴있어 상태에 의존하는 경우
예를 들어,이 솔루션은 제대로 실행되지 수있는 코드를 호출 할 수 있습니다. 자세한 내용은 Eric Lippert's excellent blog entry을 참조하십시오. 또한 this StackOverflow question and answers을 참조하십시오.
편집 : 당신은 C# 6.0을 사용하는 경우, 다음 Krzysztof's answer 갈 수있는 좋은 방법처럼 보인다.
".NET에서 개체 참조의 할당은 스레드로부터 안전합니다."라는 문구에 문제가 있습니다. 당신은 반드시 원자를 의미합니까? 내가 아는 한, 스레드 A가 변수 V에 대한 참조를 설정하면, V가 휘발성이 아니거나 읽기 및 쓰기 V를 사용하는 동안 스레드 B가 업데이트 된 참조를 변수 V에 설정한다는 것을 보증하지 않습니다. –
또한 당신의 본보기가 깨졌습니다. 스레드 A가 SomeEvent에 이벤트 핸들러를 추가 한 다음 스레드 B가 SomeEvent를 호출하면 SomeEvent가 volatile로 선언되지 않는 한 스레드 B가 SomeEvent를 null로 간주하는 경우가 있습니다. –
@Christophe, "thread-safe"로 말합니다. 하나의 쓰레드에서 객체 참조를 할당하는 것이 다른 쓰레드에 의해 일관성없는 것으로서 중단되거나 보이지 않는다. 내 업데이트에서 언급했듯이 스레드 A와 스레드 B가 항상 동일한 이벤트 뷰를 갖는다는 것은 분명히 똑같지는 않습니다. 이 모든 예는 모든 경쟁 조건이 아닌 특정 경쟁 조건을 방지하는 것입니다. – RoadWarrior