是否需要锁定对bool的访问权限,或者是否为Overkill

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不是).

Ree*_*sey 8

根据使用方式的不同,您可能需要标记布尔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)


Fal*_*nwe 5

没有一种类型是真正安全的!更准确地说,C# 规范确保读取或分配小于 4 字节的结构类型或引用是原子的。如果您的操作系统是 64 位,则 CLR 通过确保小于 8 字节的结构也能实现相同的效果,效果会更好一些。

但是,如果您不小心,任何比赋值或读取值更复杂的事情都可能被另一个竞争线程中断。

即使是这样简单的事情:

myBool = !myBool
Run Code Online (Sandbox Code Playgroud)

如果竞争线程修改 myBool 的值,可能会得到意外结果。

如果您想确保不会发生类似的事情,建议使用锁。除非您确切知道自己在做什么,否则强烈建议不要使用 volatile 关键字。查看这些 博客 文章以获取更多信息。

但是,在您的示例中,该属性除了单个写入或单个读取之外不执行任何其他操作,锁定是无用的。但如果有任何额外的治疗就不会了。


Bri*_*eon 4

你有几个选择。

  • 没做什么。
  • 使类不可变。
  • 使用普通的旧lock.
  • 将字段标记为volatile.
  • 使用这Interlocked组方法。

由于对 a 的读取和写入bool保证是原子的,因此您可能不需要执行任何操作。这在很大程度上取决于您的类的使用方式的性质。原子性不等于线程安全。这只是它的一方面。

理想的解决方案是使您的类不可变。不可变类通常是线程安全的,因为它们不能被其他线程修改(或者根本不能修改)。但有时这是不可行的。

我在列表中的下一个偏好是普通的旧lock. 获取和释放的开销非常小。事实上,我认为您会发现在大多数情况下 alock会击败 a,ReaderWriterLockSlim特别是如果您所做的只是读/写变量。我自己的个人测试表明 RWLS 的开销lock. 因此,除非读取操作异常长并且数量明显多于写入操作,否则 RWLS 将无济于事。

如果您担心锁开销,请务必将字段标记为volatile。请记住,这volatile并不是解决所有并发问题的灵丹妙药。它并非旨在替代lock.