■6802 / ) |
Re[7]: 別スレッドでShowDialogしたフォームのクローズ |
□投稿者/ れい (53回)-(2007/08/24(Fri) 00:46:24)
|
■No6798 (困ったちゃん さん) に返信 > ■No6793 (れい さん) に返信 >>フォームが閉じて作成元スレッドはメッセージを読みにいかなくなるのに >>他のスレッドがInvokeでメッセージを送り、完了を待つからです。 > > まさにその辺りの事情を詳しく知りたいのです。解説ドキュメントなどご存知でしたらご教示いただけませんでしょうか。
Undocumentedだと思います。 普通これ以上詳しく知る必要はないと思いますが、 WndProcをオーバーライドして送られてくるメッセージを見るとか、 エラーを起こしたりデバッグ環境からスタックトレースを見るとか、 ILを眺めるとかすればわかります。
> InvokeをBeginInvokeに書き換えると、速くなりすぎてForm2のクローズボタンを掴まえられなくなりました。^^; > 何か工夫して確認にトライしてみます。
Sleepでもいれてください。 進捗状況を表示するなら当然重い作業なわけで、 適当な間隔で呼べば動作します。
> ただ、このサンプルコードでは戻り値を必要としませんでしたが、一般にはFunctionをInvokeしたいケースも多々あろうかと存じます。 > この手の問題の正統?な解決策がありましたら、併せてお願いいたします。 > Form2のClosingイベントでフラグを立てて、Invokeを阻止すると効果があることは確認できたのですが、それで万全なのかが確信できないでいます。
Closingにフラグ組み込むだけではだめです。 Form.CloseされてからClosingに入る前にInvokeされたら止まります。
このControl.Invoke系のデザインは、非常に問題があると思っています。 (と言っても他のいいデザインは思いつきませんが。) Invoke系を100%安全に使おうとするなら、
・ログとかで呼び出しが重要でない場合はBeginInvoke投げっぱなし ・戻り値が欲しいならBeginInvoke+IAsyncResultでタイムアウトを設定
この二つしかありません。 メッセージの先読みとかそういった壮大な仕掛けを用意すればほぼ100%確実になりますが、 それでもプログラミング論的には間違いです。
マルチスレッドやスレッド間通信に慣れれば、 このControl.Invokeの問題がわかると思います。 そもそも、他スレッドに対して強制的にメッセージを伝え、 伝わるまで待つデザインはあり得ません。
スレッドは、死んでることはわかりますが、 生きていることを保証することはできません。 固有のUIを持つスレッドなどは特に、いつ死ぬかわかりません。 こういったスレッドへ情報を伝達し、 その伝達自体を保証する方法はありません。 「伝達できたかできなかったか知る」ことはできます。
Invokeも全く同じ問題です。 ひどいのは、Control.Invokeが、メッセージが伝達されるまで待つ点で、 つまり、Control.Invokeを安全に使う一般的方法はありません。 (実質安全である場合はありますが)
|
|