c++ memory_order_seq_cst store是否保证memory_order_relaxed加载将读取写入的值?

bfrts1fy  于 2023-02-14  发布在  其他
关注(0)|答案(2)|浏览(138)

在下面的代码中,x_value是否保证为42?

std::atomic<int> x;

Thread A:
  x.store(42, std::memory_order_seq_cst);
  wakeThreadB();

Thread B:
  int x_value = x.load(std::memory_order_relaxed);
  assert(x_value == 42);

我试过了,好像B线程总是读取正确的值,但我不确定是否有保证。

wlwcrazw

wlwcrazw1#

松弛加载不与其之前或之后的任何其他加载/存储同步。
还要注意,内存顺序语义是关于与syncronization变量相关的 * 其他工作 * 的可见性。
因此,例如,以下内容可能不正确:

std::atomic<int> x;
int y;

void func_A()
{
  y = 1;
  x.store(42, std::memory_order_seq_cst); // "releases" y = 1
}

void func_B()
{
  while (x.load(std::memory_order_relaxed) != 42) {} // does NOT "acquire" anything
  assert(y == 1); // not guaranteed
}

int main()
{
  std::thread a(&func_A), b(&func_B);
  a.join();
  b.join();
}

此处强制性说明:“* 它总是在我的机器上工作 *”并不能使它正确;如果没有同步,这就是数据竞争,一种undefined behavior形式。
但在您的特定情况下,如果您所说的wakeThreadB()是指用 Thread B 代码作为线程函数来构建std::thread示例,那么代码实际上是正确的-std::thread创建是一个同步事件(参见[thread.thread.constr]/5),因此 Thread B 中的任何加载都保证看到在 Thread B 启动之前完成的所有操作。
这意味着x的原子存储根本不重要,即使使用非原子int,代码也是正确的:

void func_B();

int x;
std::thread t;

void func_A()
{
  x = 42;
  t = std::thread(&func_B); // "releases" x = 42
}

void func_B() // "acquires" x = 42
{
  assert(x == 42); // guaranteed success
}

int main()
{
  func_A();
  t.join();
}
k5ifujac

k5ifujac2#

如果直到wakeThreadB()Thread B被锁定(如您所说,condional_variablestd::memory_order_seq_cst保证wakeThreadB()不会在x.store之前重新排序。因此,x.load将在x.store之后发生,因为在x.storeThread B锁定之前。assert(x_value == 42)将在x.load(std::memory_order_relaxed)之后发生,因为它不能由编译器重新排序,而不是因为内存顺序。

相关问题