2010-01-13 2 views
4

(나는이 문제에 대한 해결 방법을 가지고 있지만, 그것이 내가 물린 이번이 처음이 아니다, 그래서 무슨 일을 정확히 이해하기 위해 노력하고있어.)Control.Invoke는 숨겨진 ShowDialog를

에 '갇혀'하기 내 응용 프로그램에서
  • , 나는 ShowDialog 형태.
  • 클릭하면 다른 (Gui가 아닌) 스레드에서 코드를 호출하는 버튼입니다.
  • 는 비 GUI 스레드를 통해 상태 (다음 PushedReleased)을 다시 보내는 Control.Invoke
  • 형태가 Pushed를 볼 때
  • 형태가 Released 본다 form.Hide(), 그것의 외관을 변경하는 호출 단추.

경우에 따라 가끔씩은 아니지만 Gui가 아닌 스레드가 Released을 보내려고 '멈추다'가 발생합니다. 예외는 아니지만 Gui는 '작업'을 수행하지만 비 Gui 스레드와 더 이상 통신 할 수 없습니다.

스레드에 대한 (간체) 호출 스택은 다음과 같습니다

System.Threading.WaitHandle.WaitOne() 
(...) 
System.Windows.Forms.Control.WaitForWaitHandle() 
(...) 
System.Windows.Forms.Control.Invoke() 
(...) 
GuiCode.OnStatusChanged() 
(...) 
NonGuiCode.SetStatus() 

내가 ShowShowDialog을 대체하지만, 경우 문제가 사라집니다 - 흥미롭게도 - 그것은 더 좋아진다 (덜 자주 발생합니다)하지만하지 않습니다 HidePushed에 코드를 주석으로 처리하면 완전히 사라집니다. nobugz

업데이트

덕분에, 나는 (나는 오직 전에 데이터베이스에서 만난 것) 교착 상태를 발견했습니다! 분명히 Control.Invoke를 Control.BeginInvoke로 대체하면이 문제가 해결됩니다 (상태 이벤트가 가끔씩 멈추지 만 이후의 모든 통신을 차단하지는 않습니다).

답변

3

분명히 교착 상태에 빠져 있습니다. BeginInvoke() 대신 Control.Invoke()를 사용하면 항상 구석에 있습니다. 귀하의 게시물에서 교착 상태가 발생하는 이유는 무엇인지 분명하지 않습니다. 하나의 빨간색 플래그는 ShowDialog()로 표시 한 폼에 Hide()를 사용하고 있습니다. 일반적으로 대화 상자가 닫힙니다.

가장 좋은 방법은 디버깅하는 것입니다. 교착 상태가 발생할 때까지 기다린 다음 Debug + Break All을 사용하십시오. Debug + Windows + Threads를 사용하고 UI 스레드로 전환하십시오. Call Stack을보십시오. 메시지 루프 (Application.Run())를 펌핑하지 않지만 어딘가에 붙어있는 경우 (대기 핸들처럼 사용하는 것 같습니다) 교착 상태가 발생합니다.

+0

그래, 양식을 재활용하려고합니다. DialogResult를 설정하거나 닫는 것은 여전히 ​​효과가 있습니다. 이제 Invoke와 BeginInvoke의 차이점을 읽어보아야합니다. – Benjol

0

나는 이것이 내 생각에 부딪쳤다. GUI를 스레드에서

또 다른 GUI 스레드에 호출하고 해당 스레드를 ShowDialog를을 할 수 있습니다. 사용자의 GUI 환경 설정이 변경되면 (예 : 배경 회전) 교착 상태가 발생합니다.

4

Control.Invoke() 호출을 처리하려면 GUI 스레드가 Windows 메시지를 펌핑해야하지만 ShowDialog()은 블로킹 호출이므로 ShowDialog()이 반환 될 때까지이를 수행 할 수 없습니다.

Control.Invoke()

도 차단되고, 스레드는 GUI 스레드가 메시지를 선택하고 계속을 처리 할 때까지 기다려야합니다 호출. Control.Invoke()이 포함 된 코드가 대화의 해지를 허용하는 경우라면 빙고, 교착 상태가 있습니다. SosEx의 dlk 명령과 같은 교착 상태 검출기가 덤프 또는 WinDgb 세션에서 문제를 감지 할 수 있기 때문에

모든 조금 까다 롭습니다 - (가) Control.Invoke()의 GUI 스레드의 처리에 관여하는 '잠금' '암시'는 아닌 실제 WaitHandle.