在 C# 中设置一个简单的 属性 有什么非线程安全的?

What is non threadsafe about a simple property get set in c#?

我已经阅读了大量关于如何使 属性 线程安全的讨论和示例。 this threadsafe wrapper class

页面上有一个

给出的例子是这样的:

internal class MyThreadSafeCass
{
    // *** Lock ***
    private object PropertyLock = new object();

    // *** Property ***
    private int m_Property = 0;

    // *** Thread-safe access to Property using locking ***
    internal int Property
    {
        get
        {
            lock (PropertyLock)
            {
                return m_Property;
            }
        }
        set
        {
            lock (PropertyLock)
            {
                m_Property = value;
            }
        }
    }
}

很清楚这里发生了什么,锁在做什么,但我很难理解为什么需要它。为什么以下 不是 线程安全的?会出什么问题?

internal class MyThreadSafeCass
{
    // *** Property ***
    private int m_Property = 0;

    // *** Thread-safe access to Property using locking ***
    internal int Property
    {
        get
        {
            return m_Property;
        }
        set
        {
            m_Property = value;
        }
    }
}

像这样的表达式:m_Property++;在多个线程中并行 returns 不同的值。特别是在多核上 cpus.

  • 旧值被加载到 cpu 的缓存中。
  • 该值将增加 cpu
  • 新值将被保存回内存。

示例:

  • 核心一将加载值为 10
  • 核心二将与核心一同时加载值为10
  • 都加一(值为11)
  • 两者都会将数据保存回内存
  • 结果将是 11。
  • 但你期望 12

有关详细信息,请参阅 this

@Enigmativity 通过链接到 this blog about skipping locks, which in turn links to this blog about CPU reordering optimizations 获得荣誉(不幸的是,如果不是分数),这是答案的真正内容。

总而言之,CPU 可以(并且确实)对涉及更改 reads/writes 执行顺序的代码应用优化。这些更改保证在它们执行的线程内是一致的和不可察觉的。但是,它们不(不能)保证访问共享内存的多个线程之间的一致性。如初始问题中的示例所示,锁定对访问恢复一致性的共享内存施加了限制。

正如我所说,这是一个总结。我无法向上面链接的博客中的描述添加任何内容,因此请推迟任何有兴趣了解完整答案的人点击这些链接。

@Enigmativity,如果你这样 post 我仍然会接受你的回答。否则,我会接受这个答案并关闭它。