构造函数是否应该具有应用商店屏障?

Should constructors have a StoreStore barrier?

本文关键字:应用 是否 构造函数      更新时间:2023-10-16

你应该把store-store-barrier放到构造函数中吗?

下面是一个示例。最初假设global_f = f = r = 0。 一个线程 A 创建一个对象,分配给一个字段,并将其分配给一个全局变量:

class Foo {
int x;
void Foo(int x) {
this.x = x;
}
}
f = new Foo(42);
global_f = f;

另一个线程 B 从全局变量获取引用,然后读取字段。

r = global_f.x;

假设线程 B 从线程 B 读取对象引用的执行,它可以从X读取到r的什么值?总是42岁与否?

我对C++Java的行为很感兴趣。据我对记忆模型的理解,r不能保证是42。

为了确保对象的字段正确初始化,我们通常可以将存储-存储-屏障放在构造函数的末尾。这似乎是C++和Java的一个陷阱。至少对于Java来说,最终字段一切都很好,不是吗?这在实践中并不那么重要,因为至少在x86和AMD64上,商店-商店-屏障是NOP。但是,在ARM或POWER等其他架构上则不然。

在 Java 中,除非您将x字段声明为final,否则无法保证r将被42


为了确保对象的字段正确初始化,我们通常可以将存储-存储-屏障放在构造函数的末尾。这似乎是C++和Java的一个陷阱。

这是一个评论,而不是一个问题。 然而,相反的论点是,在所有构造函数的末尾放置隐式障碍会导致在各种情况下不必要的性能下降;例如

  • 对于单线程代码,
  • 对于未发布f的多线程代码
  • 对于由同步方法保护对x的访问的多线程代码。

Java 和 C++ 的内存模型是简单性和性能考虑之间的折衷。 如果你过于追求简单(即通过设计所谓的陷阱),多线程代码将无法给你人们想要/需要的那种加速。