私のアプリケーションには、テーブルをいっぱいにしてログ メッセージを送信する 2 つのバックグラウンド ワーカーがあります。これらのデータは、ReportProgress メソッドの「userState」を使用して送信されます。
これらは、次の方法でメイン スレッドに接続されます。
msg_worker.DoWork += message_worker_task;
msg_worker.ProgressChanged += msg_worker_ProgressChanged;
msg_worker.RunWorkerCompleted += worker_completed;
data_worker.DoWork += data_worker_task;
data_worker.ProgressChanged += data_worker_ProgressChanged;
data_worker.RunWorkerCompleted += worker_completed;
これらは、doWork タスクの最後に設定された 2 つの EventWaitHandle アイテムを使用して同期されます。
private void message_worker_task(object sender, DoWorkEventArgs e)
{
try
{
while( .. ){
// do work
bw.ReportProgress( 10, new String("my message to append"));
}
}
finally
{
e.Result = 0;
msg_done.Set(); // EventWaitHandle
}
}
Progress changed デリゲートは、ユーザーに表示されるコンポーネントにデータ/ログを挿入します。
さて、問題は、UI の [Quit] ボタンをクリックすると、次のように 2 つのスレッドを待機することです。
private void wait_threads()
{
int timeout = 30000;
Cursor.Current = Cursors.WaitCursor;
if (data_worker.IsBusy && !data_worker.CancellationPending)
{
data_worker.CancelAsync();
data_done.WaitOne(timeout);
}
if (msg_worker.IsBusy && !msg_worker.CancellationPending)
{
msg_worker.CancelAsync();
msg_done.WaitOne(timeout);
}
Cursor.Current = Cursors.Default;
}
これは機能しているように見えますが (コードの他の場所で使用しています)、この「終了」の場合、ログ コンポーネントにデータを挿入しようとしたという例外が発生しました。このコンポーネントは、RunWorkerCompleted デリゲートによって操作されます。
Quit がクリックされたときに実行されるコードは次のとおりです。
private void quit_Click(object sender, EventArgs e)
{
wait_threads(); // blocks until threads are finished
Close();
}
スレッドが完了するのを待っている間に、最後のイベントである RunWorkerCompleted を送信することがわかったと思います。問題は、私が自分のフォームを Close() している最中であることです。これは、フォームが正しい状態にないことを意味します。さらに、関数e.Cancelled
内のフラグを確認するworker_completed
と、false と表示されます...
関数が実行される前にRunWorkerCompletedが確実に処理されるようにするにはどうすればよいですか? Close()
(または、終了しているため、まったく処理されません)。