views:

74

answers:

3

hello,

in my class i use a BackgroundWorker. at some point i need to cancel the asynchronous operation that can be in progress and start another one immediately. the code follows. one thing that i am not sure about is the race condition that can occur if the worker completes right before i assign my lambda to RunWorkerCompleted event. if this happens my lambda will never get called. the comment in the code shows this place. any comments on how to handle this?

thanks konstantin


if (this.worker.IsBusy)
{
    RunWorkerCompletedEventHandler f = null;

    f = (s, v) =>
    {
        this.RunWorkerCompleted -= f;
        this.worker.RunWorkerAsync();
    };

    // what if worker completes right before the following statement?
    this.worker.RunWorkerCompleted += f;
    this.worker.CancelAsync();
}
else
{
    this.worker.RunWorkerAsync();
}
A: 

You could just add the RunWorkerCompleted event handler once in the ctor and also add a bool member variable 'restart' to the class. Then you can write if(IsBusy) restart = true and in your handler you check if(restart) Run(). You can define restart as volatile to avoid race conditions in that case.

I think it is not a good practice to add and remove event handlers in your case.

testalino
A: 

Maybe i'm just not smart enough to understand your code. But in my world i would built up a Queue<Action> and fill in all jobs that have to be done.

Another thread (or BackgroundWorker) will take a look at this Queue and process all the jobs in the queue sequentially (like my answer here). Maybe this is not very elegant due to the pull-mode by using a Thread.Sleep(1) in a loop.

But this could be accomplished by creating a BindingQueue<T> that derived from Queue<T> and implements IBindingList. So you could just wait for such an event, dequeue and invoke an Action till the queue is empty and start over again.

Oliver
+2  A: 

As long as this code runs on the main thread then there is no race. A BGW can only complete when the RunWorkerCompleted event handler finished running. The handler cannot start running until the main thread re-enters the message loop.

There's another kind of race though, induced by the else clause. You let the BGW start without a RunWorkerCompleted event handler. Now it can complete asynchronously since it won't be blocked. Always subscribe the event, test e.Cancelled to know what happened.

Hans Passant