【问题标题】:Does std::thread::join guarantee writes visibilitystd::thread::join 是否保证写入可见性
【发布时间】:2020-07-23 02:36:31
【问题描述】:

Std::thread::join 被称为“同步”加入的线程,但是同步并不能说明副作用的可见性,它只是控制可见性的顺序,即。在下面的例子中:

int g_i = 0;
int main()
{
  auto fn = [&] {g_i = 1;};
  std::thread t1(fn);
  t1.join();
  return g_i;
}

我们有c++ 标准中的任何保证该程序将始终返回 1 吗?

【问题讨论】:

  • @CodyGray 我不明白结束这个问题,是的,以前可能有人问过,但答案是“没关系,相信我”。我在这里想要的是一些 C++ 大师,他可以告诉我为什么这适用于一些参考/权威
  • 您没有表明您已经阅读了其他答案或您之前做过任何研究。因此,我想你没有看到他们,他们会回答你的问题。如果您正在寻找更多的东西,您应该在问题中明确说明,不仅要清楚地证明它不是重复的,还要让人们可以相应地调整他们的答案。
  • 无法回答已结束的问题,但答案是肯定的。 memory_order 中(模糊地)描述了它。虽然它似乎是在某些情况下对原子的描述(见下一条评论),但它也适用于同步的非原子。
  • 来自draft 1) §33.3.2.5-4join() - [...]同步:this * 所代表的线程的完成与 (6.8.2 ) 对应的成功 join() return[...] 2) §6.8.2.1-(8.2) [...][注:关系“is dependency-ordered before”类似于“同步”,但使用释放/消耗代替释放/获取。- 尾注][...] 3) §6.8.2.1-9 [...]评估 A 线程间如果 [...] (9.1)A 与 B 同步,或者 (9.2)A 在 B[...] 之前是依赖排序的,则在评估 B 之前发生
  • @user1810087 如果您想试一试,它已重新打开。

标签: c++ multithreading language-lawyer


【解决方案1】:

[thread.thread.member]:

void join();
效果:阻塞直到*this代表的线程完成。
同步:@代表的线程完成987654328@同步对应成功的join()返回。

由于线程执行完成与thread::join的返回同步,所以线程inter-thread happens before的完成返回:

评估A线程间发生在评估B if
AB

同步

因此happens before它:

求值 A 发生在求值 B 之前(或者,等效地,B 发生在 A 之后)如果:
A 线程间发生在 B

之前

由于(线程间)发生在传递性之前(让我跳过复制粘贴线程间发生之前的整个定义以显示这一点),在线程完成之前发生的所有事情,包括值@987654331的写入@ 进入g_i,发生在从thread::join 返回之前。反过来,从thread::join 的返回发生在读取return g_i;g_i 的值之前,这仅仅是因为thread::join 的调用在return g_i; 之前排序。同样,使用传递性,我们确定非主线程中1g_i 的写入发生在主线程中return g_i;g_i 的读取之前。

相对于在return g_i; 中读取g_i,将1 写入g_ivisible side effect

相对于 M 的值计算 B 对标量对象或位域 M 的可见副作用 A 满足条件:
A 发生在 B
之前 — XM 没有其他副作用,因此 A 发生在 XX 发生在 B 之前。
非原子标量对象或位域 M 的值,由评估 B 确定,应该是可见副作用A存储的值。

最后一句话的重点是我的,它保证从return g_i;中的g_i读取的值将是1

【讨论】:

  • OP 反复说过类似的话:这如何保证它使“所有其他线程都可以看到所有副作用?”(即使“所有其他线程”实际上并没有在问题中提及) - 所以也许一个关于在join() 中同步的线程只有两个的注释会更容易接受答案。
  • @TedLyngmo 是的,我看到了那个评论,但我想我现在不会添加任何内容。
  • 某些库调用与另一个线程执行的其他库调用同步。例如,原子存储释放与从存储([atomics.order])获取其值的加载获取同步。 [ 注意:除非在特定情况下,读取稍后的值不一定能确保可见性,如下所述。这样的要求有时会干扰有效的实施。 — 尾注 ]
  • @Salamander86 请参阅 this answer 解释注释的含义
  • 欢迎加入 2k 俱乐部。
【解决方案2】:

t1.join() 在线程执行完成之前不会返回,因此从您的示例中,g_i 保证为 1

【讨论】:

  • 但这忽略了问题..如何保证线程完成以使其写入对所有其他线程可见?
猜你喜欢
  • 2020-10-05
  • 2018-02-28
  • 2012-10-12
  • 2017-08-09
  • 1970-01-01
  • 2016-12-28
  • 2020-01-21
  • 2011-02-08
  • 2013-05-24
相关资源
最近更新 更多