2009-03-18 12 views
8

이벤트에 대한 구독자가 많은 구성 요소에서 비동기 이벤트 전달을 수행하기위한 옵션을 찾고 있습니다. 옵션을 정독하고, 난이 예제 가로 질러 :이 심각한 리소스 누수처럼비동기 적으로 이벤트 발생

public event ValueChangedEvent ValueChanged; 
public void FireEventAsync(EventArgs e) 
{ 
    Delegate[] delegates = ValueChanged.GetInvocationList(); 
    foreach (Delegate d in delegates) 
    { 
     ValueChangedEvent ev = (ValueChangedEvent)d; 
     ev.BeginInvoke(e, null, null); 
    } 
} 

을 이전 구문을 넘어 (샘플 .NET 1.1에서했다), 그것은 나에게 보인다. 완료 방법, 완료를위한 폴링 또는 기타 방법으로 EndInvoke이 호출됩니다.

제 생각에 모든 BeginInvoke에는에 해당하는 EndInvoke이 있어야합니다. 그렇지 않으면 보류중인 AsyncResult 개체 인스턴스가 비동기 이벤트 중에 제기 된 예외와 함께 (잠재적으로) 부동 상태입니다.

콜백을 제공하고 EndInvoke을 수행하는 것으로 변경하기는 쉽지만 실현할 필요는 없다는 것을 알고 있습니다. . .

비동기 exeptions 처리는 완전히 다른 문제이며 UI 스레드 (즉, InvokeRequired 등)와 동기화해야하는 필요성과 결합하여 이러한 비동기 알림을 수행하는 전체 아이디어를 수용 할 수 있습니다.

그래서, 두 가지 질문 : 나는 모든 BeginInvoke는이 EndInvoke 대응이 필요하다는 믿음에 수정

  1. 건가요?
  2. 위에서 언급 한 것 외에 Windows Forms 응용 프로그램에서 비동기 이벤트 알림을 수행하는 데있어 다른 함정이 있습니까? 반환 유형이 지정된 경우
+0

왜 비동기로 발송 하시겠습니까? 이것이 효과가 있다는 것을 보여주는 성과 분석을 했습니까? 그렇지 않으면 여러 스레드로 인해 성능이 저하 될 수 있습니다. –

+0

예, 성능 분석을 통해 비동기 처리가 이점이 있는지를 확인했습니다. –

답변

3

BeginInvoke()에 대한 호출은 EndInvoke()와 결합하지만 리소스 누수가 발생하지 않을 일을하지해야합니다. BeginInvoke()에 의해 반환 된 IAsyncResult은 가비지 수집됩니다.

이 코드에서 가장 큰 함정은 응용 프로그램을 종료하는 예외에 매우 노출되어 있다는 것입니다. 델리게이트 호출을 예외 처리기로 랩핑하여 발생하는 예외를 전파하려는 방법 (첫 번째를보고하고 집계 예외를 생성하는 등)에 대해 생각할 수 있습니다.

BeginInvoke()을 사용하여 삭제를 호출하면 이벤트 실행을 시작하기 위해 스레드 대기열에서 스레드가 제거됩니다. 즉, 이벤트는 항상 기본 UI 스레드에서 시작됩니다. 이로 인해 일부 이벤트 처리기 시나리오를 처리하기가 어려워 질 수 있습니다 (예 : UI 업데이트). 처리기는 SynchronizationContext.Send() 또는 .Post()을 호출하여 기본 UI 스레드와 동기화해야한다는 것을 인식해야합니다. 물론 다른 모든 멀티 스레드 프로그래밍 함정들도 적용됩니다.

+0

그래, 클라이언트 (즉, 이벤트 가입자)가 풀 스레드의 알림을 처리 할 준비를해야한다는 요구 사항이 여기에있어 매우 중요합니다. 클라이언트가 컨트롤을 강제하는 대신 비동기 적으로 구독해야한다고 생각합니다. –

0
  1. 번호 EndInvoke 전달에만 필요합니다. 이것 좀 봐 : thread. 또한, 세미 관련이 thread 게시했습니다.

  2. 정말 그 중 하나를 도와 드릴까요! :-) 죄송합니다.

+0

불행하게도 MSDN 스레드는 명확하지 않지만이를 추적 할 수있는 포인터를 제공합니다. –

1

잠시 생각한 끝에 Windows Forms 컨트롤에서 비동기 이벤트를 수행하는 것이 좋지 않다는 결론을 얻었습니다. Windows Forms 이벤트는 UI 스레드에서 발생해야합니다.그렇지 않으면 고객에게 과도한 부담이되며, AsyncResult 개체와 비동기 예외가 혼란 스러울 수 있습니다.

클라이언트가 자신의 비동기 처리 (BackgroundWorker 또는 다른 기술 사용)를 시작하거나 동 기적으로 이벤트를 처리하도록하는 것이 더 깔끔합니다.

물론 예외가 있습니다. 예를 들어 System.Timers.Timer은 스레드 풀 스레드에서 Elapsed 이벤트를 발생시킵니다. 그런데 초기 알림은 풀 스레드에서 시작됩니다. 일반적인 규칙은 다음과 같습니다. 초기 알림이있는 동일한 스레드에서 이벤트를 발생시킵니다. 적어도 그것은 나를 위해 가장 잘 맞는 규칙입니다. 그런 식으로 누출 물에 대한 의문의 여지가 없습니다.

관련 문제