gpt4 book ai didi

c++ - 为什么 std::atomic 初始化不进行原子释放,以便其他线程可以看到初始化值?

转载 作者:IT老高 更新时间:2023-10-28 22:10:09 28 4
gpt4 key购买 nike

proposed boost::concurrent_unordered_map 的线程清理过程中出现了一些非常奇怪的情况并且是 recounted at this blog post .简而言之,bucket_type 是这样的:

  struct bucket_type_impl
{
spinlock<unsigned char> lock; // = 2 if you need to reload the bucket list
atomic<unsigned> count; // count is used items in there
std::vector<item_type, item_type_allocator> items;
bucket_type_impl() : count(0), items(0) { }
...

然而线程清理器声称在 bucket_type 的构造和它的第一次使用之间存在竞争,特别是当 count atomic 被加载时。事实证明,如果你通过它的构造函数初始化一个 std::atomic<>,that initialisation is not atomic因此内存位置不是原子释放的,因此对其他线程不可见,鉴于它是原子的,这是违反直觉的,并且大多数原子操作默认为 memory_order_seq_cst。因此,您必须在构造后显式执行释放存储,以使用其他线程可见的值初始化原子。

是否有一些非常紧迫的原因为什么带有值消耗构造函数的 std::atomic 不使用释放语义初始化自身?如果不是,我认为这是一个库缺陷。

编辑: Jonathan 的回答更适合历史原因,但 ecatmur 的回答链接到 Alastair 关于此事的缺陷报告,以及它是如何通过简单地添加注释来说明施工报价而关闭的其他线程看不到。因此,我将把答案授予 ecatmur。感谢所有回答的人,我认为要求额外构造函数的方式很清楚,至少在文档中会突出显示值消耗构造函数存在一些不寻常的地方。

编辑 2:我最终向委员会提出这是 C++ 语言的一个缺陷,并发部分的主席 Hans Boehm 认为这不是问题,原因如下:

  1. 2014 年目前没有 C++ 编译器将消费视为与获取不同。因为在现实世界的代码中,你永远不会在不经过一些释放/获取的情况下将原子传递给另一个线程,所以原子的初始化将对使用原子的所有线程可见。我认为在编译器 catch 之前这很好,在此之前线程清理器会对此发出警告。

  2. 如果您像我一样执行不匹配的消费获取释放(我正在使用 release-inside-lock/consume-outside-lock 原子来推测性地避免不必要的释放获取自旋锁)那么你是一个足够大的男孩,知道你必须在构建后手动存储释放原子。这可能是一个公平的观点。

最佳答案

因为转换构造函数是constexprconstexpr函数不能有原子语义等副作用。

DR846 , Alastair Meredith 写道:

I'm not sure if the initialization is implied by use of constexpr keyword (which restricts the form of a constructor) but even if that is the case, I think it is worth spelling out explicitly as the inference would be far too subtle in that case.

该缺陷的解决方案(由 Lawrence Crowl 提出)是用注释记录构造函数:

[Note: Construction is not atomic. —end note]

该注释随后扩展为当前的措辞,在 DR1478 中给出了一个可能的内存竞争的示例(通过 memory_order_relaxed 操作传达原子的地址) .

转换构造函数需要是 constexpr 的原因是(主要)允许静态初始化。在 DR768我们看到:

Further discussion: why is the ctor labeled "constexpr"? Lawrence [Crowl] said this permits the object to be statically initialized, and that's important because otherwise there would be a race condition on initialization.

所以:使构造函数 constexpr 消除了静态生命周期对象上的竞争条件,代价是动态生命周期对象中的竞争只发生在相当人为的情况下,因为要发生竞争,动态生命周期原子对象的内存位置必须以不会导致原子对象的 value 也同步到该线程的方式传递给另一个线程.

关于c++ - 为什么 std::atomic 初始化不进行原子释放,以便其他线程可以看到初始化值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25609858/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com