用于增加/模仿布尔值的互锁,这安全吗?

Posted

技术标签:

【中文标题】用于增加/模仿布尔值的互锁,这安全吗?【英文标题】:Interlocked used to increment/mimick a boolean, is this safe? 【发布时间】:2009-09-07 13:27:37 【问题描述】:

我只是想知道一个开发人员(后来离开)的代码是否可以,我想他想避免加锁。这与仅使用直接锁定之间是否存在性能差异?

    private long m_LayoutSuspended = 0;
    public void SuspendLayout()
    
        Interlocked.Exchange(ref m_LayoutSuspended, 1);
    

    public void ResumeLayout()
    
        Interlocked.Exchange(ref m_LayoutSuspended, 0);
    

    public bool IsLayoutSuspended
    
        get  return Interlocked.Read(ref m_LayoutSuspended) != 1; 
    

我在想这样的事情用锁会更容易吗?它确实会被多个线程使用,因此决定使用锁定/互锁。

【问题讨论】:

【参考方案1】:

是的,从比赛的角度来看,您正在执行的操作是安全的,到达 m_LayoutSuspended 字段,但是,如果代码执行以下操作,则出于以下原因需要锁定:

if (!o.IsLayoutSuspended)  // This is not thread Safe .....

  o.SuspendLayout();   // This is not thread Safe, because there's a difference between the checck and the actual write of the variable a race might occur.
  ...
  o.ResumeLayout();
 

一种更安全的方法,它使用CompareExchange 来确保没有发生竞争条件:

private long m_LayoutSuspended = 0;
public bool SuspendLayout()

    return Interlocked.CompareExchange(ref m_LayoutSuspended, 1) == 0;


if (o.SuspendLayout()) 

  ....
  o.ResumeLayout();

或者更好的是简单地使用锁。

【讨论】:

Interlocked.CompareExchange does not have an overload with two arguments 也许你的行应该写成return Interlocked.CompareExchange(ref m_LayoutSuspended, 1, 0) == 0; 它有 also been pointed out to me 将其更改为 return Interlocked.Exchange(ref m_LayoutSuspended, 1) == 0; 也可以解决问题。【参考方案2】:

我个人会使用 volatile 布尔值:

private volatile bool m_LayoutSuspended = false;
public void SuspendLayout()

    m_LayoutSuspended = true;


public void ResumeLayout()

    m_LayoutSuspended = false;


public bool IsLayoutSuspended

    get  return m_LayoutSuspended; 

再说一次,正如我最近在其他地方所承认的那样,volatile 并不像我想象的那样。我怀疑这没关系:)

即使您坚持使用 Interlocked,我也会将其更改为 int...没有必要让 32 位系统可能难以实现 64 位写入原子,因为他们可以轻松地使用 32位...

【讨论】:

@Jon:我很好奇,您能否详细说明“易失性并不像我想象的那样”? 只是强调一下,volatile long 将是安全的(在 32 位系统上)。 volatile 仅在一组线程专门写入一个字段并且一组线程专门读取一个字段时才有用,除了它没有多大用处。 @Pop:你的答案绝对是一个更清晰的答案,但你是否同意 volatile 布尔值与原始代码一样有效? @Jon:是的,volatile bool 应该和原始代码一样安全(但更有效)。但是,比较然后更改的场景并不安全;为此,您需要 Pop 的代码。 (两者都比锁更有效。)

以上是关于用于增加/模仿布尔值的互锁,这安全吗?的主要内容,如果未能解决你的问题,请参考以下文章

跨多个线程和 cpu 安全地修改和读取布尔值的选项都有哪些?

用于存储布尔值的 MySQL 数据类型

用于存储布尔值的 MySQL 数据类型

用于存储布尔值的 MySQL 数据类型

检查整数是不是为 0 并返回布尔值的简短方法

c#中布尔值和布尔值的区别? [复制]