I'm using a BackgroundWorker to perform a long computation (only one such computation at a time).
The user has the possibility of cancelling the worker (calling worker.CancelAsync).
In the worker.DoWork method I periodically check for the cancel pending flag and then return from the method.
Then the Completed event is raised from the worker and I can check that the worker was cancelled. Furthermore, and that is the important thing, I do some extra cleanup when a cancel is detected.
I am sure there could be problem if the user cancels the worker and it's already returned from the DoWork method. In that case I would really like to know that the worker was cancelled so I could cleanup...
Is there a better way to handle the cancel procedure, with cleanup, of a worker ?
Your DoWork
event handler shoud periodically check BackgroundWorker.CancellationPending
, and set DoWorkEventArgs.Cancel
to true before returning if it was cancelled.
Your RunWorkerCompleted
event handler should check the RunWorkerCompletedEventArgs.Cancelled
property to determine if the DoWork
event handler cancelled (set DoWorkEventArgs.Cancel
to true).
In the event of a race condition, it may happen that the user requested cancellation (BackgroundWorker.CancellationPending
is true) but the worker didn't see it (RunWorkerCompletedEventArgs.Cancelled
is false). You can test these two properties to determine that this has occurred, and do whatever you choose (either treat it as successful completion - because the worker did actually finish successfully, or as a cancellation - because the user has cancelled and doesn't care any more).
I don't see any situation where there is any ambiguity about what happened.
EDIT
In response to the comment - if there are several classes that need to detect CancellationPending
, there's no really no alternative to passing to these classes a reference to a type such as BackgroundWorker
that allows them to retrieve this information. You can abstract this into an interface, which is what I generally do as described in this response to a question about BackgroundWorkers. But you still need to pass a reference to a type that implements this interface to your worker classes.
If you want your worker classes to be able to set DoWorkEventArgs.Cancel
you will need to either pass a reference to this around, or adopt a different convention (e.g. a boolean return value or custom exception) that allows your worker classes to indicate that cancellation has occurred.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With