如果中间有线程连接,为什么不能使用宽松的原子操作来同步内存?

Why can't you use relaxed atomic operations to synchronize memory, if there is a thread join in between?

我正在看 Herb Sutter 的演讲:https://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-2-of-2

看两个例子(大约 1:15 标记),一个对我有意义,另一个对我来说没有意义。

第一个例子(有道理):

注意 count 是一个原子整数。

在这里,对 load/store 计数使用宽松的内存排序据说是可以的,因为线程退出发生在从线程上的连接返回之前。这意味着松弛添加发生在松弛加载之前。

子线程:

while (...) {
  if (...) {
    count.fetch_add(1, memory_order_relaxed);
  }
}

主线程:

int main() {
  launch_workers();
  join_workers();
  cout << count.load(memory_order_relaxed);
}

第二个例子(不清楚):

注意 dirtystop 是原子布尔值。

这里讲的是dirty上的store和load必须分别使用release和acquire排序,因为dirty是用来发布一些数据,这些数据是为了清理而读取的。

子线程:

while(!stop.load(memory_order_relaxed)) {
  if (...) {
    // publish some data
    dirty.store(true, memory_order_release)
  }
}

主线程:

int main() {
  launch_workers();
  stop = true;
  join_workers();
  if (dirty.load(memory_order_acquire)) {
    // read published data to clean up
  }
}

我的问题是,在第二个示例中,为什么不能在线程退出和从线程的连接返回之间应用相同的 'happens before' 关系来同步内存?

我认为它可以在 dirty 的操作上使用宽松的内存排序的方式是:

[子线程做一些工作,包括发布数据]

[子线程退出]-(发生在之前)->[Return从子线程加入join_workers()调用]

[主线程都将 dirty 视为 true 并且可以安全地读取已发布的数据以进行清理]

在 1:17:25 附近,他说“现在,因为你碰巧知道我通过加入线程获得了 release-acquire,所以我在其中注入了 release-acquire;这可能已经足够好了,你可以去放松一下”。所以他似乎在说,最后,如果 dirty 以宽松的内存顺序访问实际上没问题。