2012-07-19 8 views
5

작업자 스레드의 이벤트를 주기적으로 촬영하는 외부 구성 요소를 사용하고 있습니다. 내 이벤트 핸들러에서는 Dispatcher를 사용하여 주 스레드에서 일부 메소드를 호출합니다. 프로그램이 종료되고 외부 부품 폐기()의, 때로는 중단 (그리고 만 볼 수 및 작업 관리자에서 살해 할 수 있습니다) 프로그램 때, ... 잘 그러나작업 스레드가 주 스레드에서 호출하려고 할 때 교착 상태가 발생했습니다.

private void HandleXYZ(object sender, EventArgs e) 
{ 
    ... 
    if(OnTrigger != null) 
     dispatcher.Invoke(OnTrigger, new TimeSpan(0, 0, 1), e); 
} 

작동합니다.

작업자 스레드가 디스패처 호출을 기다리는 동안 "구성 요소"가 주 스레드에서 이벤트가 반환 될 때까지 기다리고 있습니다 (Dispose() 메서드에 유지됨) 메인 스레드에 대한 언급 된 호출 (디스패처에서 멈 춥니 다 .Invoke-line).

당분간은 작동이 느려지지만 잘못된 것처럼 느껴지는 Invoke에 시간 초과를 추가하여 종료 문제를 해결했습니다. 이와 같은 작업을보다 명확하게 처리 할 수 ​​있습니까? 메인 스레드가 종료되기 전에 다른 스레드의 작업에 시간이 걸릴 수 있습니까? 나는 "분리"종료하기 전에 경우에 시도했지만 발송자이기 때문에 그 (수) 프로그램이 종료 시작할 때 이미 대기, 도움이되지 않습니다

...

PS : 외부 구성 요소는 여기에 내가 소스 코드에 액세스 할 수 없다는 것을 의미합니다 ...

+0

사용하십시오 문단 다음에 – Shai

+1

많은 – Vedran

답변

6

예, 이것은 일반적인 교착 상태의 원인입니다. Dispatcher가 Dispatcher 루프를 종료 했으므로 중단됩니다. 더 이상 Invoke 요청에 응답하지 않습니다. 빠른 치료법은 대신 BeginInvoke를 사용하는 것입니다. 호출 타겟이 실행을 마칠 때까지 기다리지 않습니다. 또 다른 방법은 작업자 스레드의 IsBackground 속성을 True로 설정하여 CLR이 작업 스레드를 종료하도록하는 것입니다.

다음은 빠른 수정으로 잘 작동합니다. 확실히 당신의 dev 머신에 있지만, 만약 당신이 교착 상태를 보지 않거나 레이스를 스레딩하지 않는다고해도 여전히 잘못 될 수 있다는 잔소리가 있다면 은 아니며은 존재하지 않는다는 것을 증명합니다. 당신은 작업자 스레드가 종료되고 더 이상 이벤트를 발생시킬 수 없음을 확인 때까지

  • 출구에 메인 쓰레드를 허용하지 않습니다 : 완전히 안전하게 작업을 수행하는 두 개의 "좋은"방법이 있습니다. This answer이 패턴을 보여줍니다.

  • Environment.Exit()을 사용하여 강제로 프로그램을 종료하십시오.이것은 입니다. 매우입니다. 그러나 매우입니다. UI 스레드가 제 2의 시민 일 뿐인 스레드 프로그램을 많이 사용하는 경우에만 사용할 수 있습니다. 이상한 것은 적절한 접근 방식으로 들릴지도 모르는 새로운 C++ 언어 표준은이를 프로그램을 종료하는 지원되는 방법으로 향상 시켰습니다. this answer에서 자세한 내용을 볼 수 있습니다. 정리 기능을 등록하는 방법에 유의하십시오. AppDomain.ProcessExit 이벤트와 비슷한 작업을 수행해야합니다. 첫 번째 글 머리 기호에 집중하십시오.

+0

좋은 답변입니다! BeginInvoke-way가 타임 아웃보다 나을 것 같아요. – FrankB

+0

다음과 같은 의미입니까? 프로그램이 종료되지 않고 주 스레드가 이벤트를 기다리는 경우 ... 주 스레드가 "적극적으로"대기하고 있지만 디스패처가 주 스레드로 호출을 가져 오지 않습니까? – FrankB

+0

이것이 원래 질문과 어떤 관련이 있는지 잘 모르겠습니다. 그러나 주 스레드에서 어떤 종류의 "대기"도 교착 상태를 일으킬 수 있습니다. Invoke() 호출은 주 스레드가 유휴 상태이고 Dispatcher 루프를 실행하는 경우에만 전달 될 수 있습니다. –

1

이벤트 구독에 대해서는 particluar 객체가 더 이상 필요하지 않다는 것을 알 때이를 정리하는 것이 좋습니다. 그렇지 않으면 메모리 누수가 발생할 위험이 있습니다. weak event pattern (MSDN)을 살펴볼 수도 있습니다.

코드를 모른 채 교착 상태 자체에 대해서만 추측 할 수 있습니다.

나는 HandleXYZ()을 범인으로 보지 않으며, 귀하의 IDisposable() 구현을 확인하고 싶습니다. MSDN documentation을보고 구현과 비교하십시오.

구현의 어딘가에서 비 결정적 인 GarbageCollector의 타이밍에 의존하는 메소드 호출이 있다고 가정합니다. 때로는 문제가 해결 될 수도 있지만 언젠가는 그렇지 않을 수도 있습니다.

+0

감사합니다 도움이 될 코드를 붙여 넣기 ...하지만 불행히도 폐기()의 코드 (외부 부품) – FrankB

+1

문제는, @FrankB 나를 사용할 수 없습니다, 어떤 정리를합니까? 일반적으로,'IDispoeable()'을 구현 한 클래스는 항상 정리해야합니다. 해당 타사 구성 요소가 무언가를 기다리고 있다면 자체 코드가 일부 리소스를 제대로 릴리스하지 않았을 수도 있습니다. –

+0

다른 구성 요소는 이벤트가 반환 될 때까지 대기하며 내 이벤트 핸들러는 대기중인 구성 요소에 의해 차단 된 주 스레드를 기다립니다. Dispatcher가 주 스레드 대기를 중지하도록 강제 할 수있는 경우에만 정리 작업이 솔루션입니다. 타임 아웃을 설정하는 것 외에 다른 작업을 수행 할 수 있습니까? – FrankB

관련 문제