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

问题描述

我正在观看Herb Sutter的这个谈话:https://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-2-of-2

看两个例子(大约1:15马克),一个我有意义,另一个对我没有意义。

一个示例(很有意义):

注意count一个原子整数。

在这里,使用宽松的内存顺序进行加载/存储被认为是可以的,因为线程退出发生在从线程上的联接返回之前。这意味着轻松的添加发生在轻松的负载之前。

子线程:

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

主线程:

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

第二个示例(不清楚):

注意dirtystop是原子布尔值。

在这里,谈话说dirty上的存储和加载必须分别使用释放和获取顺序,因为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
  }
}

我的问题是,在第二个示例中,为什么不能在线程出口和从线程上的联接返回返回的线程之间应用相同的“先发生”关系来同步内存?

我认为它可以与dirty的操作中的宽松内存顺序一起使用的方式是:

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

[子线程退出] -(之前发生过)-> [在join_workers()调用中从子线程的联接返回]

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

解决方法

在1:17:25左右,他说:“现在,因为您碰巧知道我通过加入线程获得了发布授权,所以我在其中注入了发布授权;这可能就足够了,并且您可以放松一下”。因此,他似乎最后说的是,如果使用宽松的内存顺序访问dirty,那真的很好。