Yes, this code is wrong - the outcome is not really defined, but it would be quite reasonable for it to throw an exception at the mrEvent.WaitOne()
, since mrEvent
is the almost-certainly-now-disposed ManualResetEvent
. Technically there's a chance that the worker thread was all ready to go, and the worker thread did its "some processing..." faster than the primary thread did the "some other processing...", but: I wouldn't rely on it. So in most cases: mrEvent
is dead already.
As for how to avoid this: perhaps this simply isn't a scenario for using
. But it occurs that since the worker thread does a WaitOne
, the worker thread's WaitOne
cannot complete before the primary thread performs the mre.Set()
call - so you could exploit that and move the using
to the worker:
var mre = new ManualResetEvent(false);
var bgWkr = new BackgroundWorker();
bgWkr.DoWork += delegate(object sender, DoWorkEventArgs e)
{
using(var mrEvent = e.Argument as ManualResetEvent)
{
// some processing...
mrEvent.WaitOne();
}
// broadcast an event
};
bgWkr.RunWorkerAsync(mre);
// some other processing...
// hook into the same event
mre.Set();
Note, however, that this raises an interesting question of what happens if the primary thread throws an exception in the "some other processing..." - the call to mre.Set()
would never be reached, and the worker thread would never exit. You might want to do the mre.Set()
in a finally
:
var mre = new ManualResetEvent(false);
try {
var bgWkr = new BackgroundWorker();
bgWkr.DoWork += delegate(object sender, DoWorkEventArgs e)
{
using(var mrEvent = e.Argument as ManualResetEvent)
{
// some processing...
mrEvent.WaitOne();
}
// broadcast an event
};
bgWkr.RunWorkerAsync(mre);
// some other processing...
}
finally {
// hook into the same event
mre.Set();
}