4

(この問題の回避策はありますが、噛まれたのは初めてではないので、何が起こっているのかを正確に理解しようとしています。)

  • 私のアプリケーションから、私ShowDialogはフォームです。
  • フォームにはボタンがあり、クリックすると別の(GUI以外の)スレッドのコードが呼び出されます。
  • Pushed非GUIスレッドはReleased、Control.Invokeを介してステータス(および)を送り返します。
  • フォームがを見るとPushed、を呼び出しますform.Hide()
  • フォームReleasedにが表示されると、ボタンの外観が変わります。

何が起こるかというと、常にではありませんが、Gui以外のスレッドがを送信しようとして「スタック」することがありReleasedます。例外はありませんが、Guiは「作業」を続行しますが、どちらの方向でも、非Guiスレッドとのそれ以上の通信はできません。

スレッドの(簡略化された)コールスタックは次のようになります。

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

に置き換えるShowDialogと問題は解決しますが、興味深いことに、問題は改善されます(発生頻度は低くなります)が、 onShowを実行するコードをコメントアウトしても完全には解決しません。HidePushed

アップデート

nobugzのおかげで、デッドロックを発見しました(これまでデータベースでしか遭遇していませんでした)。どうやらControl.InvokeをControl.BeginInvokeに置き換えると、この問題は解決します(ステータスイベントは「スタック」することがありますが、後続のすべての通信をブロックするわけではありません)。

4

3 に答える 3

4

呼び出しを処理するControl.Invoke()には、GUIスレッドはWindowsメッセージを送信する必要がありますが、呼び出しをブロックしているため、戻るShowDialog()までそれを実行できません。ShowDialog()

Control.Invoke()もブロックされており、それを呼び出すスレッドは、GUIスレッドがメッセージを取得して処理するまで待機する必要があります。を含むコードがControl.Invoke()ダイアログの却下を可能にするものである場合、ビンゴ、デッドロックがあります。

SosExのdlkコマンドのようなデッドロック検出器はダンプまたはWinDgbセッションから問題を検出できないため、これはすべて少し注意が必要です。GUIスレッドの処理に関係する「ロック」Control.Invoke()は実際のではなく「暗黙」WaitHandleです。

于 2010-07-29T19:24:39.983 に答える
3

明らかに、あなたはデッドロックと戦っています。BeginInvoke()の代わりにControl.Invoke()を使用する場合、これは常に角を曲がったところです。何があなたの投稿からデッドロックを引き起こしているのか、私にはわかりません。1つの危険信号は、ShowDialog()で表示したフォームでHide()を使用していることです。通常、ダイアログは閉じます。

最善の方法は、デバッグすることです。デッドロックが発生するまで待ってから、Debug +BreakAllを使用します。デバッグ+ウィンドウ+スレッドを使用して、UIスレッドに切り替えます。コールスタックを見てください。メッセージループ(Application.Run())をポンピングしていないが、どこかでスタックしている場合(使用しているように見える待機ハンドルなど)、デッドロックが発生します。

于 2010-01-13T12:05:20.150 に答える
0

これだと思うものに出会ったばかりです。

GUIスレッドから、別のGUIスレッドを呼び出し、そのスレッドにShowDialogを実行させます。ユーザーのGUI設定が変更された場合(バックグラウンドローテーターなど)、デッドロックが発生します。

于 2010-02-16T19:00:43.597 に答える