【问题标题】:Herb Sutter Atomic Weapons "Why Standalone Fences are Suboptimal"Herb Sutter Atomic Weapons “为什么独立围栏不是最理想的”
【发布时间】:2016-04-05 18:36:28
【问题描述】:

在他的 talk 关于内存屏障(栅栏)的结尾,他给出了以下示例(注意global 不是原子类型):

// thread 1                                     // thread 2
widget *temp = new widget();
global = temp;
                                                global->do_something();
                                                global->do_something_else();

后来他说我们应该有如下完整的栅栏:

   // thread 1                                     // thread 2
   widget *temp = new widget();
XX mb();   XXXXXXXXXXXXXXXXXXXXX
   global = temp;
                                                   temp2 = global;
                                                XX mb(); XXXXXXXXXXXXXXXX  
                                                   temp2->do_something();
                                                   temp2 = global;
                                                XX mb(); XXXXXXXXXXXXXXXX
                                                   temp2->do_something_else();

我想知道为什么在线程 1 中你需要一个屏障? global 取决于 temp 并且编译器不会将 global = temp; 移动到 temp 的构造之上。我认为需要内存屏障的一个原因是语句global=temp; 可以在new widget() 的构造中间以某种方式完成,然后线程2 会看到部分构造的global。在构建新的widget 的过程中是否可以安排分配给global?还是内存屏障是其他原因造成的?

同样在线程 2 中,在temp2->do_something(); 之后你不需要另一个屏障吗?与当前转换的形式一样,以下语句在执行过程中仍然可以重新排序:

                                                   temp2 = global;
                                                XX mb(); XXXXXXXXXXXXXXXX 

                                                   temp2 = global;
                                                   temp2->do_something();

                                                XX mb(); XXXXXXXXXXXXXXXX
                                                   temp2->do_something_else();

这不是你想要的,因为现在你只在一个temp2 上调用成员函数,而不是在执行do_something_else() 之前从global 读取一个新值。

如果线程 2 中不可能进行这种重新排序,那么如果 temp2->do_something(); 不能在 temp2 = global; 之前重新排序,为什么我们首先需要线程 2 中的障碍。

【问题讨论】:

    标签: c++ multithreading


    【解决方案1】:

    我想知道为什么在线程 1 中你需要一个屏障?全局取决于温度 并且编译器不会移动 global = temp;以上建设 反正是温度。

    这与temp 的内部成员的初始化有关。由于 CPU 缓存和重新排序,此处没有内存屏障 global 可能具有新的地址 temp,但 temp 指向的内存可能未初始化。

    至于第二个问题,很明显

    temp2->do_something();
    temp2 = global;
    

    不能重新排序为

    temp2 = global;
    temp2->do_something();
    

    因为它会对完全不同的对象做一些事情!

    【讨论】:

    • 好的。正如我所怀疑的那样。关于线程 2 的问题呢? temp2->do_something(); 之后你还需要另一个障碍吗?
    • @Rich,也回答了这个问题。
    • 我不太明白你对线程 2 的评论。为什么不能重新排序?编译器和硬件是否尊重此处读取操作后的写入顺序?以及涉及哪些不同的对象?
    • @Rich,我不确定你不明白什么。 temp2 是指向特定对象的指针。当你要求编译器先用这个对象做某事,然后用别的东西替换指针时,编译器不能先用别的东西替换指针,然后用新对象做一些事情!
    • @Rich,通过 'do_something` 完成的修改对其他线程可见(毕竟,它们是在全局对象中完成的)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-18
    • 2016-05-21
    相关资源
    最近更新 更多