【问题标题】:Are reference assignment and reading atomic operations?引用赋值和读取是原子操作吗?
【发布时间】:2011-04-28 10:08:15
【问题描述】:

我发现了几个关于同一主题但与一般变量(值和引用类型)相关的问题 this question 接受的回答说:

CLI 规范的第 I 部分第 12.6.6 节规定:“当对一个位置的所有写访问都被访问时,符合标准的 CLI 应保证对不大于本机字大小的正确对齐的内存位置的读写访问是原子的。大小一样。”

引用变量(即类)是指针,等于原生字长,但我有几个疑问:

是否保证引用位于正确对齐的内存位置?

我不明白最后一部分。这是什么意思? “...当对一个位置的所有写访问的大小相同时。”

简而言之,在下面的代码中,obj2是否保证在循环的每次迭代中都有效?

class MyClass
{
    private OtherClass m_Object;

    void Thread1()
    {
        while(true)
        {
            OtherClass obj1 = new OtherClass();
            m_Object = obj1;
        }
    }

    void Thread2()
    {
        while (true)
        {
            OtherClass obj2 = m_Object;
            // Is obj2 guaranteed to be valid?
            obj2.Check();
        }
    }
}

【问题讨论】:

    标签: c# .net multithreading visual-studio-2010


    【解决方案1】:

    是的,一切都保证正确对齐,除非你故意不对齐东西,这意味着引用分配/读取保证是原子的。

    CLI 规范的第 12.6.6 节继续说:

    除非显式布局控制(请参阅 第二部分(控制实例 Layout)) 用于更改默认值 行为,数据元素不大于 自然字长(a的大小 native int) 应正确 对齐。对象引用应为 就好像它们存储在 本机字长。

    在规范的第 12.6.2 节中还有关于对齐等的更多细节。

    请注意,在您的示例代码中,线程 2 中的读取保证是原子的,但保证实际看到线程 1 所做的任何更改:不强制每个线程执行内存屏障或易变性可以使用自己的 m_Object 字段“视图”,而不会看到其他线程所做的更改。

    因此,例如,线程 1 可能正在(原子)写入它自己的 m_Object 视图,但数据实际上只保存在寄存器或 CPU 缓存中,从未提交到主内存。同样,线程 2 也可以(原子)读取m_Object,但实际上是从寄存器或 CPU 缓存而不是主内存读取。

    【讨论】:

    • 这很有趣,谢谢。如果在循环内部,不是直接读取/分配 m_Object 变量,而是调用了实际执行读取/分配的方法,该怎么办?波动性问题还会存在吗?
    • @Jaime:是的,除非有某种强制同步——易失性字段、内存屏障、锁、Interlocked 调用等——那么它仍然可能发生。 (根据我的经验,这种事情并不经常咬人,但它偶尔确实,所以最好完全避免它。)
    猜你喜欢
    • 2011-02-13
    • 2011-10-18
    • 1970-01-01
    • 1970-01-01
    • 2019-05-05
    • 2011-01-18
    • 2012-03-28
    • 1970-01-01
    • 2018-01-06
    相关资源
    最近更新 更多