The way to cancel a BackgroundWorker's operation is to call BackgroundWorker.CancelAsync()
:
// RUNNING IN UI THREAD private void cancelButton_Click(object sender, EventArgs e) { backgroundWorker.CancelAsync(); }
In a BackgroundWorker.DoWork event handler, we check BackgroundWorker.CancellationPending
:
// RUNNING IN WORKER THREAD void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) { while (!backgroundWorker.CancellationPending) { DoSomething(); } }
The above idea is all over the web, including on the MSDN page for BackgroundWorker.
Now, my question is this: How on earth is this thread-safe?
I've looked at the BackgroundWorker class in ILSpy — CancelAsync()
simply sets cancellationPending to true without using a memory barrier, and CancellationPending
simply returns cancellationPending without using a memory barrier.
According to this Jon Skeet page, the above is not thread-safe. But the documentation for BackgroundWorker.CancellationPending says, "This property is meant for use by the worker thread, which should periodically check CancellationPending and abort the background operation when it is set to true."
What's going on here? Is it thread-safe or not?
BackgroundWorker, is a component in . NET Framework, that allows executing code as a separate thread and then report progress and completion back to the UI.
The BackgroundWorker class allows you to run an operation on a separate, dedicated thread. Time-consuming operations like downloads and database transactions can cause your user interface (UI) to seem as though it has stopped responding while they are running.
The BackgroundWorker class exposes the DoWork event, to which your worker thread is attached through a DoWork event handler. The DoWork event handler takes a DoWorkEventArgs parameter, which has an Argument property.
It is because BackgroundWorker inherits from Component which inherits from MarshalByRefObject. An MBRO object may reside on another machine or in another process or appdomain. That works by having the object impersonated by a proxy that has all of the exact same properties and methods but whose implementations marshal the call across the wire.
One side effect of that is that the jitter cannot inline methods and properties, that would break the proxy. Which also prevents any optimizations from being made that stores the field value in a cpu register. Just like volatile does.
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