Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How is BackgroundWorker.CancellationPending thread-safe?

Tags:

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?

like image 564
Tom Avatar asked Aug 06 '11 11:08

Tom


People also ask

Is BackgroundWorker threaded?

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.

What is BackgroundWorker?

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.

What is BackgroundWorker in Winforms?

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.


1 Answers

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.

like image 61
Hans Passant Avatar answered Oct 04 '22 04:10

Hans Passant