C# と VB.NET の質問掲示板

わんくま同盟

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト


(過去ログ 18 を表示中)
■6843 / )  Control.Invokeが使えない件。
□投稿者/ れい (58回)-(2007/08/24(Fri) 19:16:28)

分類:[.NET 全般] 

こちら(http://bbs.wankuma.com/index.cgi?mode=al2&namber=6760)で話してたんですが、
皆さんの意見を聞きたいので、タイトルと内容を合わせてスレッド立てます。

タイトルの通り、「Control.Invokeが使えない」件に関して、
私の事実誤認であるとか、同意であるとか、皆さんの意見をください。

Control.InvokeやEndInvokeを何も考えずに使うと、
Controlを廃棄した際にデッドロックします。
Invokeがウィンドウメッセージを送り、返事を待ってる間に
Controlが廃棄された場合、いつまで待っても返事が返ってこないからです。
これは
http://osdir.com/ml/windows.devel.dotnet.clr/2004-04/msg00157.html
http://www.microsoft.com/japan/msdn/community/gdn/ShowPost-26227.htm
などなど、かなり既出の件です。

この対策をいろいろ考えたのですが、
Control.Invokeを安全に使える方法が全く存在せず、
Invokeを使うこと自体が間違いであるという結論に至ってしまいました。

ControlやFormはいつ廃棄されるのか、
Invokeする側(Invoker)からはわかりません。
Invokeされる側(Invokee)でフラグを立てて回避しようとしても、
Invokeメソッド内で実際にウィンドウメッセージを送るまでの間に
ControlやFormが死んでしまうとデッドロックします。

WorkerThreadをInvokerとする場合も同様で、
WorkerThreadが死ぬ前にControlが死ぬ可能性のある場合は、
WorkerThreadがInvokeでデッドロックし、残ってしまいます。
Controlは、WM_DESTROYやWM_QUITで、いつでも死ぬ可能性があり、
Controlが死ぬ前にWorkerThreadが死ぬのを保証するには、Abortし終了を待つしかありませんが、
その間にInvokeされてる場合もありうるのでダメです。

いろいろ考えましたが、どうやってもControl.Invokeを安全には使えませんでした。
代替方法はBeginInvokeを投げっぱなしにするか、EndInvokeをタイムアウト付きで呼ぶことでした。

ですが、
http://msdn2.microsoft.com/ja-jp/library/757y83z4(VS.80).aspx
http://www.atmarkit.co.jp/fdotnet/dotnettips/312ctrlinvoke/ctrlinvoke.html
http://codezine.jp/a/article.aspx?aid=139#invoke
http://dobon.net/vb/dotnet/programing/progressdialog.html
などなど、
ネット上にも、MSDNにもInvokeを使ったサンプルはたくさんあります。
見る限りどれもデッドロックを引き起こすコードで、
いくつかは検証してみましたが、実際にデッドロックを引き起こしました。
MSDNのサンプルでさえ、Formを閉じたときにスレッドがWaitのまま残りました。

私が検証した限りでは、安全に使うことはできませんでしたし、
理論上できないのではないかと私は思っています。
もし安全に呼ぶ方法が一つでもあるなら存在意義がありますが、
一つも無いなら、ただ邪魔なだけのメソッドです。

だれか発言力のある偉い人が、「Control.Invokeはダメ」って言ってくれれば安心するんですが、
見当たりません。
私一人が思ってるだけ、言ってるだけでは、自分自身も説得できなくて。
誰か偉い人、「ダメ」って言ってくれませんか?

また、「きちんと使えてる。お前のチエが猫並みなだけ」って人がいるなら、
是非猫にチエをご教授ください。
返信 編集キー/


管理者用

- Child Tree -