次のコードは簡単な概念証明です。 Windowsフォームアプリケーションには、クリーンアップを実行するFormClosingイベントハンドラがあります。アプリケーションは、Control.Invokeを使用してフォームに書き込むいくつかのスレッドを起動します。私はControl.BeginInvokeを使用することができることを知っていますが、何が起こるかをよりよく理解し、別の解決策を見つけたいと思います。Control.Invokeを使用した予期しないブロック条件
List<Thread> activeThreadlist;
volatile bool goOnPolling = true;
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
goOnPolling = false;
Thread.Sleep(1000);
foreach (Thread element in activeThreadlist)
if (element.IsAlive)
element.Abort();
}
フラグがスレッドにループを停止するためにはfalseに設定されている、彼らが終了する時間を持って、1つはまだ生きているならば、それはアボートで終了します。
ここが他のスレッドによって実行されるコードである:彼らは睡眠時に終了しないようにフォームがControl.Invoke上のスレッドブロックを閉じているとき症例の約50%において
while (goOnPolling)
{
//some long elaboration here
if (!goOnPolling) continue;
aControl.Invoke(new Action(() =>
{
//display some result about the elaboration
}));
if (!goOnPolling) continue;
//some long elaboration here
}
Abortが呼び出されます。私は、呼び出しの前にgoOnPollingをチェックして、99.999%のケースで十分だったと思ったが、間違っていた。コードに記載されているように、スレッドは長いエラボレーション(少なくとも100ms)を行いますので、私は期待していますgoOnPollingはそれらの間に変更される可能性があります。なぜ私は間違っていますか?追加のスレッドを作成するBeginInvokeに繰り返しない別の簡単なソリューションがありますか?
更新
私はタイトルが間違っていた実現のコメントを読んだ後。私は最初にデッドロックを書きましたが、予期せぬ(私にとっては)ブロック状態に過ぎません。最初は1000ミリ秒間待ってからスレッドがまだ生きていた理由を理解できませんでしたので、アボートを見つけてください。 InvokeとBeginInvokeの違いを完全に誤解しています。
@ジョンB
私は休憩ががを続けるが、そのコードは内部しばらく(goOnPolling)ブロックであるので、私は、より多くの何も唯一のいくつかのCPUサイクルを節約することができなかったよりも適しています同意するものとします。
理由がよくわからない理由goOnPollingはInvokeの初期段階で変更されますか?私が長い精緻化を実行する場合、それはほとんどの時間に起こるはずです。
'BeginInvoke'は追加のスレッドを作成するべきではなく、既存の* UIスレッドに作業をキューイングするだけです。新しいスレッドを作成することは、 'BeginInvoke'が行うように設計されていることに完全に反するでしょう。 –
最後の文章は本当ですか?私が知る限り、 'Invoke'と' BeginInvoke'の両方がUIスレッド上で実行されます。戻り前に 'Invoke'ブロックのみが実行されます。即ち、「Invoke」=「BeginInvoke」+実行を待つ。あなたは 'delegate'' Invoke'/'BeginInvoke'と混同されるかもしれません、https://stackoverflow.com/questions/229554/whats-the-difference-between-invoke-and-begininvokeを見てください。 'Control.Invoke'を使用する唯一の理由は、呼び出されたアクションを完了して呼び出しスレッドを続行する必要がある場合です。 – Rotem
私は100%陽性です。 'Invoke'はメッセージループの実行をキューに入れ、完了するまで待機します。 'BeginInvoke'は全く同じことをしますが、完了するまでブロックしません。おそらくあなたのデッドロックがどこから来ているのでしょうか。あなたのUIスレッドは子スレッドで待機しており、子スレッドはUIを完了するのを待っています。 –