在c#中设置一个简单的属性是不线程安全的

本文关键字:属性 简单 安全 线程 一个 设置 | 更新日期: 2023-09-27 18:06:03

我已经阅读了大量关于如何使属性线程安全的讨论和示例。页面上有一个线程安全包装器类

给出的例子是:

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;
        }
    }
}

在c#中设置一个简单的属性是不线程安全的

一个表达式:m_Property++;在多个线程中,parallel返回不同的值。特别是在多核cpu上。

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

的例子:

  • core one将加载值为10
  • 核心2将与核心1同时加载值为10
  • 均加1(值为11)
  • 都将数据保存回内存
  • 结果将是11.
  • 但你期望12

查看详细信息

@Enigmativity通过链接到这个关于跳过锁的博客而获得了荣誉(如果不是分数,不幸的是),这个博客又链接到这个关于CPU重新排序优化的博客,这是答案的真正内容。

总之,cpu可以(并且确实)对代码进行优化,包括改变读/写的执行顺序。这些更改保证在执行它们的线程内保持一致且不易察觉。然而,它们不能(不能)保证访问共享内存的多个线程之间的一致性。锁,如第一个问题中的示例所示,对访问这个共享内存施加限制,从而恢复一致性。

正如我所说,这是一个总结。我不能在上面链接的博客中添加任何内容,所以我会推迟任何有兴趣知道完整答案的人跟随这些链接。

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