And*_*dre 12 c# multithreading locking readerwriterlockslim
我有一个主要设计为POCO类的类,各种线程和任务可以读取其值,只有其他只偶尔更新这些值.这似乎是ReaderWriterLockSlim的理想场景.
问题是,在类中,如果属性需要是线程安全的,如果属性是bool,那是否过度杀伤?如果它是一个int会发生什么?约会时间?
public class MyClass
{
private bool _theValue = false;
private ReaderWriterLockSlim _theValueLock = new ReaderWriterLockSlim();
public bool TheValue
{
get
{
bool returnVal = false;
try
{
_theValueLock.EnterReadLock();
returnVal = _theValue;
}
finally
{ _theValueLock.ExitReadLock(); }
return returnVal;
}
set
{
try
{
_theValueLock.EnterWriteLock();
_theValue = value;
}
finally
{ _theValueLock.ExitWriteLock(); }
}
}
}
Run Code Online (Sandbox Code Playgroud)
所有这些代码都是矫枉过正的,而且简单......
public bool TheValue { get; set; }
Run Code Online (Sandbox Code Playgroud)
......会足够吗?因为Type是bool,安全吗?如果是的话,什么时候变得不安全?字节?诠释?约会时间?
编辑
我的基本架构是具有此类存储状态.也许有一个服务负责对这个类进行写操作.所有其他类都可以根据此状态数据读取和执行其逻辑.我会尽力确保所有数据都是一致的,但如下所述,我主要担心的是数据的原子性和危险性.
结论
感谢大家的回应,一切都很有价值.我主要担心的是写入/读取的原子性(即担心痉挛).对于.NET平台,如果有问题的变量是一个小于4个字节的内置值类型,则读取和写入是原子的(例如,short和int很好,long和double不是).
根据使用方式的不同,您可能需要标记布尔volatile.这将需要您的财产的支持领域.
您现在应该不需要处理这个问题ReaderWriterLockSlim,因为它不到32位(假设您正在使用AutoLayout,有关详细信息,请参阅此文章,或者,最详细地说,标题为"内存访问的原子性 "一节在ECMA 335规范中).如果您使用的是大于此类型的类型,则需要某种形式的同步.
我建议:
public class MyClass
{
private volatile bool _theValue = false;
public bool TheValue
{
get { return _theValue; }
set { _theValue = value; }
}
}
Run Code Online (Sandbox Code Playgroud)
没有一种类型是真正安全的!更准确地说,C# 规范确保读取或分配小于 4 字节的结构类型或引用是原子的。如果您的操作系统是 64 位,则 CLR 通过确保小于 8 字节的结构也能实现相同的效果,效果会更好一些。
但是,如果您不小心,任何比赋值或读取值更复杂的事情都可能被另一个竞争线程中断。
即使是这样简单的事情:
myBool = !myBool
Run Code Online (Sandbox Code Playgroud)
如果竞争线程修改 myBool 的值,可能会得到意外结果。
如果您想确保不会发生类似的事情,建议使用锁。除非您确切知道自己在做什么,否则强烈建议不要使用 volatile 关键字。查看这些 博客 文章以获取更多信息。
但是,在您的示例中,该属性除了单个写入或单个读取之外不执行任何其他操作,锁定是无用的。但如果有任何额外的治疗就不会了。
你有几个选择。
lock.volatile.Interlocked组方法。由于对 a 的读取和写入bool保证是原子的,因此您可能不需要执行任何操作。这在很大程度上取决于您的类的使用方式的性质。原子性不等于线程安全。这只是它的一方面。
理想的解决方案是使您的类不可变。不可变类通常是线程安全的,因为它们不能被其他线程修改(或者根本不能修改)。但有时这是不可行的。
我在列表中的下一个偏好是普通的旧lock. 获取和释放的开销非常小。事实上,我认为您会发现在大多数情况下 alock会击败 a,ReaderWriterLockSlim特别是如果您所做的只是读/写变量。我自己的个人测试表明 RWLS 的开销比lock. 因此,除非读取操作异常长并且数量明显多于写入操作,否则 RWLS 将无济于事。
如果您担心锁开销,请务必将字段标记为volatile。请记住,这volatile并不是解决所有并发问题的灵丹妙药。它并非旨在替代lock.