« 先読みキューの重複チェックを入れた | トップページ | 言ったそばから »

2009/10/23

EBt for Wiindows で、EBtWin.exe が終わらなくなる不具合が直った

まぁ、予期せぬデッドロックが起きていたというありがちな理由です。

しかしなぁ、予期せぬと言うところがねぇ。本当に予期せぬと言うか、理論的には発生しないデッドロックが発生しているのがどうも、ね。

.NET のアプリケーションは、基本的にシングルスレッドで動く訳なのですが、EBt for Windows(以下、EBtWin)はマルチスレッドで動いています。

んで、.NETでは、メインのGUIを制御するスレッド(スレッド1とする)以外からは、GUIの制御は基本的にできません。基本的にというところがミソで、アプリケーションが作成したスレッド(スレッド2とする)からGUIの制御をする場合、Invokeというメソッドを使う事で実現しています。

で、Invoke の実装の仕組みはブラックボックスなのだが、多分、スレッド1のイベントキューに、スレッド2のGUI制御メソッドを呼び出すというリクエストを保存する事で実現しているのではないかと勝手に想像している。

今回の不具合だが、結構複雑で、こんな順序でデッドロックが発生していたのではないかと想像している。

1)スレッド1がスレッド2に対してスレッド停止要求を出す。
2)スレッド1は、スレッド2の終了待ちをする(Thread.Join()を呼び出す)。
3)スレッド2で、Invokeメソッドが呼び出される。→スレッド1のイベントキューにInvokeのリクエストが保存される。
4)スレッド2が、イベントキューの終了待ちをする

てな感じで、スレッド1・スレッド2が見事両方とも Wait 状態になりデッドロックになった…と思っている。
スレッド1がwaitだったらInvokeリクエストを消費してくれればいいのだが、どうやら、そうでもないらしい。多分、スレッド1のイベント処理が終了しないといけないのだろうと勝手に判断。しかも、4)に突入したら、復帰しないような雰囲気。

まぁ、でも問題はこんなに単純ではないようで、想像した問題の回避策をコードに組み込んでも、やっぱりデッドロックする。何でだよ、何が悪いんだよ、教えてくれよ .NET よ。

GUIライブラリをスレッドセーフで構築するのは難しいのは十分にわかる。なので、Invoke みたいな仕組みを導入するのも仕方がないと思っている。けど、なんか、詰めが甘くないかなーという気がするのですよ、こういう動作を見ると。Microsoft の詰めの甘さが出ているなーという感じ。

で、最終的に打った回避策。

t.Join( xxxx ); // 理論的にデッドロックしていなかったら終了しているだけの時間
if ( t.IsAlive ){
t.Abort();
}

汚いと思わば汚いと思え。私も汚いと思っている。あー、ここまで汚いコード書くのはやっぱり嫌だなぁ。

|

« 先読みキューの重複チェックを入れた | トップページ | 言ったそばから »

コメント

コメントを書く



(ウェブ上には掲載しません)




トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/50935/46565158

この記事へのトラックバック一覧です: EBt for Wiindows で、EBtWin.exe が終わらなくなる不具合が直った:

« 先読みキューの重複チェックを入れた | トップページ | 言ったそばから »