为什么std::barrier会进行内存分配?

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

1
我在标准中没有看到任何需要分配任何东西的内容。 - Nicol Bolas
展示您获取这些信息的来源会很有帮助。 - bolov
@bolov Valgrind - Simon Gauvin
@SimonGauvin,你应该将这些信息与你测试的编译器/标准库/系统一起添加。 - bolov
1个回答

20

虽然一个天真的屏障可以作为std::barrier对象的一部分使用恒定的存储量来实现,但是现实世界中的屏障实现使用具有> O(1)存储但具有更好并发属性的结构。天真的、恒定存储的屏障可能会遭受大量线程争用同一个计数器的困扰。这种争用可能导致O(N)运行时从屏障释放线程。

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

想象一下增强的树形屏障实现并不太困难,这些实现意识到缓存/套接字/内存总线层次结构,并根据线程的物理位置将线程分组在树中,以最小化跨核心、跨芯片和跨套接字轮询到最小。

另一方面,闩锁是一种更轻量级的同步工具。然而,我不太确定为什么闩锁会被禁止分配-cppreference指出,

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接