2

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吗?或者我应该在每个和块中使用locking吗?getset

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

编辑:

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

再说一遍,您是否建议使用volatile、 或locking 或其他任何东西?.. 当使用bool属性原子性得到保证时,只剩下第二个问题(读取最新值),那么您如何正确解决这个问题? 当你有非原始类型的属性时怎么办?你lock在每个getset块中都放了 s 吗?

4

4 回答 4

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;

推理:原子性是由字段是 type 的事实确保的bool,因此不需要locking。制作它们volatile将确保任何线程都将读取当前值-未缓存-以防另一个线程对其进行了修改。我认为这是volatile关键字的确切用途(也是唯一有效的用途),对吧?

于 2012-09-12T08:23:25.817 回答
3
public bool CancellationPending { get; private set; }
public bool IsBusy { get; private set; }
public bool WorkerReportsProgress { get; set; }
public bool WorkerSupportsCancellation { get; set; }

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

不,这仅适用于CancellationPendingand IsBusy,不适用于其他人。
它们都是布尔值,保证是原子的。原子性在这里就足够了。

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

于 2012-09-11T15:50:06.373 回答
1

尽管我认为那里有更好的选择,例如将 Tasks 与 svick 提到的另一个调度程序一起使用。

如果您想继续走这条路,您绝对应该使用锁定字段而不是 volatile 字段,因为volatile 不会按照您的想法进行。 哦,这家伙说了一些关于永远不要制造不稳定领域的事情......

您可以根据访问特性使用您最喜欢的同步原语(lock、Mutex、Interlocked、ReaderWriterLockSlim 等)代替 volatile。

于 2012-09-11T15:58:27.703 回答
0

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

另一种选择是使用互锁类,它允许对整数和布尔值进行线程安全修改。如果这就是您使用属性的全部内容,那么它是一个简单的解决方案。

于 2012-09-11T15:53:49.890 回答