由于某些原因,我正在实施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
吗?或者我应该在每个lock
和get
块中使用set
吗?
我认为这应该是非常常见的情况 - 使属性(最好是自动属性)是线程安全的。请注意,在此示例中,所有属性都是原子类型。
修改
澄清我需要的东西:我需要确保所有线程始终读取属性的最新值。请参阅:https://stackoverflow.com/a/10797326/1081467
再次,您是否建议使用volatile
或lock
或其他任何内容?...当使用bool
属性时,保证原子性,所以只留下第二个问题(阅读最新值),那么如何正确解决这个问题呢?当你拥有非原始类型的属性时呢?您是否在lock
和get
块中添加了set
?
答案 0 :(得分:6)
我想出了以下实现。请评论您是否认为这是一个最佳解决方案:
//========== 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
类型的事实确保了原子性,因此不需要lock
。使它们volatile
将确保任何线程将读取当前值 - 而不是缓存 - 以防另一个线程修改它。我认为这是volatile
关键字的确切目的(仅限有效用途),对吗?
答案 1 :(得分:3)
public bool CancellationPending { get; private set; }
public bool IsBusy { get; private set; }
public bool WorkerReportsProgress { get; set; }
public bool WorkerSupportsCancellation { get; set; }
所以他们可能被不同的线程访问/修改
不,这只适用于CancellationPending
和IsBusy
,而不适用于其他人
他们都是布尔,保证是原子的。原子性就足够了。
原始Backgroundworker的所有属性都记录为不线程安全 请参阅this page底部附近。
答案 2 :(得分:1)
虽然我认为有更好的选择,例如将任务与其他调度程序一起使用,如svick所述。
如果你想继续这条路径,你肯定应该使用锁定而不是易变的字段作为volatile does not do what you think。 Oh and this guy said something about never making a volatile field...
取决于易失性,您可以使用您喜欢的同步原语(锁定,互斥锁,互锁,ReaderWriterLockSlim等等),具体取决于访问特征。
答案 3 :(得分:0)
一种简单的方法是为每个要保证线程安全的属性使用互斥对象。在get和set属性中,使用Monitor.Enter(declaredObjectMutext)和Monitor.Exit(declaredObjectMutex)。完成后,这将使您的属性成为线程安全的(所有get和set调用都将阻塞调用,直到完成任何其他线程)。
另一种选择是使用Interlocked Class,它允许线程安全地修改整数和bools。如果这就是您使用属性的全部内容,那么这是一个简单的解决方案。