为什么 std::barrier 会分配?

Why does std::barrier allocate?

提问人:Simon Gauvin 提问时间:6/28/2022 最后编辑:Jarod42Simon Gauvin 更新时间:6/28/2022 访问量:1179

问:

为什么 std::barrier 在堆上分配内存,而 std:latch 不?

它们之间的主要区别在于可以重用而不能重用,但我找不到解释为什么这会使前者分配内存。std::barrierstd::latch

C++ 多线程 std c++20

评论

1赞 Nicol Bolas 6/28/2022
我在标准中没有看到任何要求它分配任何东西。
0赞 bolov 6/29/2022
显示您从哪里获得此信息会很有帮助。
0赞 Simon Gauvin 6/29/2022
@bolov 瓦尔格林德
0赞 bolov 6/29/2022
@SimonGauvin,您应该将此信息与测试此信息的编译器/标准库/系统一起添加。

答:

20赞 nanofarad 6/28/2022 #1

虽然朴素屏障确实可以使用恒定量的存储作为对象的一部分来实现,但实际的屏障实现使用具有> O(1) 存储但更好的并发属性的结构。幼稚的恒定存储屏障可能会受到同一计数器上大量线程争用的影响。这种争用可能导致 O(N) 运行时从屏障中释放线程。std::barrier

作为“更好”实现的一个例子,gcc libstdc++ 实现使用树屏障。这避免了在所有线程之间共享的单个计数器/互斥锁上的争用,并且树屏障可以在对数时间内传播“屏障完成,释放时间”信号,但代价是需要线性空间来表示线程树。

不难想象增强的树型屏障实现,这些实现可以识别缓存/套接字/内存总线层次结构,并根据线程的物理位置对树中的线程进行分组,以最大程度地减少跨内核、跨芯片和跨套接字轮询所需的最低限度。

另一方面,闩锁是一种更轻量级的同步工具。但是,我不太确定为什么禁止分配闩锁 - cppreference 状态,

闩锁类是向下的计数器类型std::ptrdiff_t

这将指示它不应该分配(即它只是一个计数器,没有空间来保存指向已分配对象的指针)。另一方面,标准中的 [thread.latch] 只说“闩锁维护一个内部计数器,该计数器在创建闩锁时初始化”,而不禁止它分配。