c# - 如何轻松使这个计数器属性线程安全?

标签 c# thread-safety

我在只有计数器的类中有属性定义,这必须是线程安全的,这不是因为 getset 不在同一个锁中,如何做到这一点?

    private int _DoneCounter;
    public int DoneCounter
    {
        get
        {
            return _DoneCounter;
        }
        set
        {
            lock (sync)
            {
                _DoneCounter = value;
            }
        }
    }

最佳答案

如果您希望以保证 DoneCounter = DoneCounter + 1 不受竞争条件影响的方式实现属性,则不能在属性的实现中完成。该操作不是原子操作,它实际上是三个不同的步骤:

  1. 检索 DoneCounter 的值。
  2. 加1
  3. 将结果存储在 DoneCounter 中。

您必须防止在任何这些步骤之间发生上下文切换的可能性。锁定在 getter 或 setter 内部不会有帮助,因为该锁的范围完全存在于其中一个步骤(1 或 3)中。如果您想确保所有三个步骤一起发生而不被打断,那么您的同步必须涵盖所有这三个步骤。这意味着它必须发生在包含所有这三个方面的上下文中。这可能最终成为不属于任何包含 DoneCounter 属性的类的代码。

使用您的对象的人有责任注意线程安全。通常,不能以这种方式使具有读/写字段或属性的类成为“线程安全的”。但是,如果您可以更改类的接口(interface),从而不需要 setter,则可以使其更加线程安全。例如,如果您知道 DoneCounter 只会递增和递减,那么您可以像这样重新实现它:

private int _doneCounter;
public int DoneCounter { get { return _doneCounter; } }
public int IncrementDoneCounter() { return Interlocked.Increment(ref _doneCounter); }
public int DecrementDoneCounter() { return Interlocked.Decrement(ref _doneCounter); }

关于c# - 如何轻松使这个计数器属性线程安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9011908/

相关文章:

c# - 单元测试Elastic Search Nest客户端-BulkAll

c# - Xamarin ContentView 构造函数

java - JAVA 中的双重检查锁定

c++ - 在 C++11 的析构函数中锁定互斥量

java - 在这种情况下如何有效地使用线程?

c# - 网络上数据库的 SQL 连接字符串

c# - 未在 C# 中捕获的未处理异常

iphone - 我的 iPhone 应用程序真的需要锁定吗?

python - 如何在 Python 中验证我的线程安全模型?

c# - 跳过映射空属性