I have two background workers in my application that fill up a table and send log messages. They transmit these data using the "userState" of the ReportProgress method.
They are connected to the main thread through:
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;
They are synchronized using two EventWaitHandle items that they set at the end of their doWork task:
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
}
}
The Progress changed delegates insert data/log in the components that are visible to the user.
Now, the problem is that when I click on the Quit button in my UI, I wait on those 2 threads like this:
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;
}
This seems to be working (I use it at other places in the code), but in this "quitting" case, I have an exception raised, saying that I tried to insert data into the log component I have. This component is manipulated by the RunWorkerCompleted delegate.
The code which gets executed when Quit is clicked is this:
private void quit_Click(object sender, EventArgs e)
{
wait_threads(); // blocks until threads are finished
Close();
}
I think I figured out that while waiting for the threads to complete, they send a last event: the RunWorkerCompleted.
The problem is that I'm in the process of Close() 'ing my form, which means the form is not in a correct state.
What's more, if I check the e.Cancelled
flag in the worker_completed
function, I see it as false...
What can I do to make sure the RunWorkerCompleted is handled before my Close()
function gets executed? (or rather, is not handled at all, because we're quitting).