多くのスレッドが GUI を更新するために呼び出すことができる次のコードがあります。
MethodInvoker del = () => { lblInfo.Text = tmp; };
lblInfo.BeginInvoke(del);
(lblInfo は GUI スレッドによって作成されます)
また、GUI スレッドによって実行されるボタン クリックでこのメソッドが呼び出されます。
public void Stop()
{
isStopping = true;
crawler.Join();
foreach (Thread t in txtWorkers)
{
t.Join();
}
indexer.Join();
lblStatus.Text = "Stopped";
lblInfo.Text = "";
}
停止ボタンのクリックで1回100回以上プログラムがデッドロックします。デッドロックを見たときはデバッグしていなかったので、さまざまなスレッドの状態についてはわかりませんが、参加しているすべてのスレッドが最終的に
isStopping
値をチェックして終了するポイントに到達することはほぼ確実です。これにより、に問題がある可能性があると思いますが、BeginInvoke
実際には見つけることができません。それを呼び出すスレッド (クローラーとインデクサー) がブロックされないように、非同期にする必要があります。Stop()
GUI スレッドが実行中で、 からの呼び出しも実行する必要がある場合はどうなりBeginInvoke
ますか? これが問題でしょうか?参加しているスレッドについて表示されないものはありますか?
編集: 提案された変更後のコードの外観:
public void Stop()
{
/*
...disable GUI
*/
isStopping = true; // Declared as volatile
lblStatus.Text = "Stopping...";
// Creating a thread that will wait for other threads to terminate
Task.Factory.StartNew(() =>
{
crawler.Join();
foreach (Thread t in txtWorkers)
{
t.Join();
}
indexer.Join();
// Adjust UI now that all threads are terminated
MethodInvoker del = () =>
{
/*
...enable GUI
*/
lblStatus.Text = "Not Running";
isStopping = false;
};
lblStatus.BeginInvoke(del);
});
}
機能しているようです。デッドロックが解消されることを願っています...