简体   繁体   English

如何使公共属性线程安全?

[英]How to make public properties thread-safe?

I'm implementing the BackgroundWorker replacement for some reason, and I have to implement following public properties: 我出于某种原因正在实现BackgroundWorker替换,我必须实现以下公共属性:

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

I'm sure you know what purpose they serve in BackgroundWorker . 我确定你知道它们在BackgroundWorker用途。 So they might be accessed/modified by different threads. 所以它们可能被不同的线程访问/修改。 I'm concerned about how to "protect" them for multithreading. 我担心如何为多线程“保护”它们。 I thought declaring them as volatile would be enough, but volatile can't be applied to automatic properties. 我认为将它们声明为volatile是足够的,但volatile不能应用于自动属性。

What should I do? 我该怎么办? Should I create private fields for these properties, and declare them volatile ? 我应该为这些属性创建私有字段,并声明它们是volatile吗? Or should I use lock ing inside each get and set blocks? 或者我应该在每个getset块中使用lock

I think this should be pretty common scenario - making properties (preferably automatic properties) thread-safe. 我认为这应该是非常常见的情况 - 使属性(最好是自动属性)线程安全。 Note that all properties are of atomic type in this example. 请注意,在此示例中,所有属性都是原子类型。

EDIT: 编辑:

To clarify what I need: I need to be sure that all threads always read the most up-to-date value of the property. 澄清我需要的东西:我需要确保所有线程始终读取属性的最新值。 See this: https://stackoverflow.com/a/10797326/1081467 请参阅: https//stackoverflow.com/a/10797326/1081467

So again, do you advice using volatile , or lock ing, or anything else?.. When using the bool properties atomicity is guaranteed, so only the second problem is left (reading the up-to-date values), so how do you solve this correctly? 所以再次,你建议使用volatile ,或lock ,还是其他什么?..当使用bool属性时,保证原子性,所以只留下第二个问题(读取最新值),那你怎么做解决这个问题吗? What about when you have properties of non-primitive types? 当你拥有非原始类型的属性时呢? Do you put lock s in each get and set blocks? 你在每个getset块中放置lock吗?

I came up with the following implementation. 我想出了以下实现。 Please comment whether you think it is an optimal solution: 请评论您是否认为它是最佳解决方案:

//========== 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;

Reasoning: atomicity is ensured by the fact that the fields are of type bool , so no need for lock ing. 推理:由于字段是bool类型,所以确保原子性,因此不需要lock Making them volatile will ensure that any thread will read current value - not cached - in case another thread has modified it. 使它们volatile将确保任何线程将读取当前值 - 而不是缓存 - 以防另一个线程修改它。 I think this is the exact purpose (and only valid use) of volatile keyword, right? 我认为这是volatile关键字的确切目的(并且只有有效使用),对吧?

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

So they might be accessed/modified by different threads 所以它们可能被不同的线程访问/修改

No, that would only apply to CancellationPending and IsBusy , not to the others. 不,这只适用于CancellationPendingIsBusy ,而不适用于其他人。
And they are all booleans, guaranteed to be atomic. 他们都是布尔,保证是原子的。 Atomicity is enough here. 原子性就足够了。

All of the properties of the original Backgroundworker are documented as not thread-safe. 原始Backgroundworker的所有属性都记录为不是线程安全的。
See near the bottom of this page . 请参见本页底部附近。

Though I think that there are better options out there such as using Tasks with anothe scheduler as svick mentioned. 虽然我认为有更好的选择,例如使用任务与其他调度程序作为svick提到。

Should you want to continue on this path you should definitely use locking and not volatile fields as volatile does not do what you think . 如果你想继续这条路径,你肯定应该使用锁定而不是易失性字段,因为volatile不会按你的想法行事 Oh and this guy said something about never making a volatile field... 哦,这家伙说了一些关于永远不会变得不稳定的领域......

Instead of volatile you can use your favourite synch primitive (lock, Mutex, Interlocked, ReaderWriterLockSlim, etc...) depending on the access characteristics. 您可以根据访问特征使用您最喜欢的synch原语(lock,Mutex,Interlocked,ReaderWriterLockSlim等),而不是volatile。

A simple way is to have mutex objects for each property that you want to be thread safe. 一种简单的方法是为每个要保证线程安全的属性使用互斥对象。 In the get and set properties, use a Monitor.Enter(declaredObjectMutext), and Monitor.Exit(declaredObjectMutex). 在get和set属性中,使用Monitor.Enter(declaredObjectMutext)和Monitor.Exit(declaredObjectMutex)。 Once done, this will make your properties thread-safe (all calls to get and set will be blocking calls until any other threads are finished). 完成后,这将使您的属性成为线程安全的(所有get和set调用都将阻塞调用,直到完成任何其他线程)。

Another option is to use the Interlocked Class, which allows for thread-safe modification of integers, and bools. 另一种选择是使用Interlocked Class,它允许线程安全地修改整数和bools。 If thats all you're using with your properties, its an easy solution. 如果您使用的是所有属性,那么这是一个简单的解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM