为什么
它们之间的主要区别在于,
std::barrier
在堆上分配内存,而 std::latch
不会呢?它们之间的主要区别在于,
std::barrier
可以被重复使用,而 std::latch
不能,但我找不到为什么前者会分配内存的解释。std::barrier
在堆上分配内存,而 std::latch
不会呢?std::barrier
可以被重复使用,而 std::latch
不能,但我找不到为什么前者会分配内存的解释。虽然一个天真的屏障可以作为std::barrier
对象的一部分使用恒定的存储量来实现,但是现实世界中的屏障实现使用具有> O(1)存储但具有更好并发属性的结构。天真的、恒定存储的屏障可能会遭受大量线程争用同一个计数器的困扰。这种争用可能导致O(N)运行时从屏障释放线程。
作为“更好”的实现示例,gcc libstdc++实现使用了树形屏障。这避免了所有线程共享单个计数器/互斥锁的争用,并且树形屏障可以在对数时间内传播“屏障完成,释放时间”信号,代价是需要线性空间来表示线程树。
想象一下增强的树形屏障实现并不太困难,这些实现意识到缓存/套接字/内存总线层次结构,并根据线程的物理位置将线程分组在树中,以最小化跨核心、跨芯片和跨套接字轮询到最小。
另一方面,闩锁是一种更轻量级的同步工具。然而,我不太确定为什么闩锁会被禁止分配-cppreference指出,
闩锁类是一个类型为
std::ptrdiff_t
的向下计数器
这表明它不应该分配(即它只是一个计数器,没有空间来保存指向已分配对象的指针)。另一方面,标准中的[thread.latch]仅表示“闩锁维护一个在创建时初始化的内部计数器”,没有禁止它进行分配。