如何使公共属性线程安全



由于某种原因,我正在实现BackgroundWorker替换,并且我必须实现以下公共属性:

public bool CancellationPending { get; private set; }
public bool IsBusy { get; private set; }
public bool WorkerReportsProgress { get; set; }
public bool WorkerSupportsCancellation { get; set; }

我相信你知道他们在BackgroundWorker的目的是什么。因此,它们可能会被不同的线程访问/修改。我关心的是如何为多线程"保护"它们。我认为将它们声明为volatile就足够了,但volatile不能应用于自动属性。

我该怎么办?我应该为这些属性创建专用字段,并将它们声明为volatile吗?还是应该在每个getset块中使用locking?

我认为这应该是非常常见的场景——使属性(最好是自动属性)线程安全。请注意,在本例中,所有属性都是原子类型的。

编辑:

为了澄清我需要什么:我需要确保所有线程始终读取属性的最新值。请参阅:https://stackoverflow.com/a/10797326/1081467

再说一遍,你建议使用volatilelocking还是其他什么?。。当使用bool属性时,原子性是有保证的,所以只剩下第二个问题(读取最新的值),那么如何正确解决这个问题呢?如果您具有非基元类型的属性,该怎么办?您是否在每个getset块中放置lock

我提出了以下实现。请评论您是否认为这是一个最佳解决方案:

//========== Public properties ==================================================//
public bool CancellationPending { get { return _cancellationPending; } private set { _cancellationPending = value; } }
public bool IsBusy { get { return _isBusy; } private set { _isBusy = value; } }
public bool WorkerReportsProgress { get { return _workerReportsProgress; } set { _workerReportsProgress = value; } }
public bool WorkerSupportsCancellation { get { return _workerSupportsCancellation; } set { _workerSupportsCancellation = value; } }
//========== Private fields ==================================================//
private volatile bool _cancellationPending;
private volatile bool _isBusy;
private volatile bool _workerReportsProgress;
private volatile bool _workerSupportsCancellation;

推理:原子性是由字段类型为bool来保证的,所以不需要locking。使它们成为volatile将确保任何线程都能读取当前值,而不是缓存的值,以防另一个线程修改了它。我认为这就是volatile关键字的确切目的(也是唯一有效的使用),对吧?

public bool CancellationPending { get; private set; }
public bool IsBusy { get; private set; }
public bool WorkerReportsProgress { get; set; }
public bool WorkerSupportsCancellation { get; set; }

因此,它们可能会被不同的线程访问/修改

不,这只适用于CancellationPendingIsBusy,不适用于其他
它们都是布尔,保证是原子的。原子性在这里已经足够了。

原始Backgroundworker的所有属性都被记录为而不是线程安全
请参阅本页底部附近的。

尽管我认为还有更好的选择,比如像svick提到的那样,将Tasks与另一个调度器一起使用。

如果你想继续走这条路,你肯定应该使用锁定而不是volatile字段,因为volatile不会像你想的那样。哦,这个家伙说了一些关于永远不要制造一个不稳定的领域。。。

您可以根据访问特性使用您喜欢的同步原语(锁、互斥、Interlocked、ReaderWriterLockSlim等),而不是volatile。

一个简单的方法是为您想要线程安全的每个属性设置互斥对象。在get和set属性中,使用Monitor.Enter(declardObjectMutext)和Monitor.Exit(declaredObjectMutex)。一旦完成,这将使您的属性线程安全(所有对get和set的调用都将阻止调用,直到任何其他线程完成)。

另一种选择是使用Interlocked类,它允许对整数和布尔进行线程安全修改。如果这就是你在房产中使用的全部内容,那么这是一个简单的解决方案。

最新更新