【问题标题】:Memory Ordering, Out of other Execution and Multi thread Safety内存排序、其他执行和多线程安全
【发布时间】:2017-12-12 17:18:17
【问题描述】:

我最近一直在阅读有关内存重新排序的内容。我的问题是关于多线程场景。考虑下面的例子:

A = 0;
B = 0;

Thread 1 on Processor 1                       Thread 2 on Processor 2

    A = 100;                                      while(B== 0);
    B = 1;                                       //access A here

我一直在 X86-64 Windows 平台上进行编码,从未考虑过可以重新排序 A 和 B 的存储(在编译器级别或硬件级别),我可能最终在线程 2 中得到 B = 0 并找到 A仍然是 0。并且从来没有遇到过这样的代码的任何问题或讨厌的错误。是不是因为 x86-x64 是强排序的,windows C 编译器也是。

对于在具有弱排序内存的任何其他平台上执行这样的代码,我是否需要确保在锁中更新和访问 A 和 B(假设底层锁实现使用内存屏障并确保锁是只有在所有先前的加载和存储在所有处理器内核上都可见后才释放)。

谢谢

【问题讨论】:

    标签: multithreading memory strict-weak-ordering


    【解决方案1】:

    是不是因为 x86-x64 是强排序的,windows C 编译器也是。

    确实,X86 是一个不允许存储重新排序的强排序 CPU。所以所有的 CPU 内核都会遵守编译器发出的顺序。

    但是,B 在处理器 1 上被修改,而在处理器 2 上读取。没有同步的 C 内存模型不允许这样做(尝试最大限度的编译器优化,它可能会停止工作)。

    虽然锁定可用于在内核之间进行同步,但它可能会出现问题,因为您正在使用 B。如果在获取锁时发生这种情况,处理器 1 将无法更新该值。

    正确的解决方案是使Batomic。这将保证所有级别的正确排序。

    【讨论】:

    • LMimsey 您的意思是最大限度地优化可以启用编译器级别的重新排序。我没有得到“这在 C 内存模型中是不允许的”。强排序 x86 应该保证当 B = 1 时 A = 100,这就是上面的例子想要得到的。
    • 我的问题的下一部分,在内存弱排序的平台上,我是否需要注意在锁内更新 A 和 B。确保所有 OS 平台上的锁定原语在内部在锁定释放逻辑中插入内存屏障,否则即使锁定也可能无法防止硬件内存访问重新排序。
    • 2 个或更多线程对单个内存位置的读/写访问违反了内存模型规则(也称为数据竞争)。结果是未定义的行为。例如,由于您的编译器可能不希望在核心 2 上更新 B,它可能只是将其从循环中取出。循环将永远不会退出。
    • 如果B 是原子的(C11 原子库),即使在最弱的平台上也能保证工作。编译器将插入必要的内存屏障。
    猜你喜欢
    • 2014-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-15
    • 1970-01-01
    相关资源
    最近更新 更多