【发布时间】:2021-07-06 02:19:16
【问题描述】:
在 C++20 中,我们可以在原子变量上休眠,等待它们的值发生变化。
我们通过使用std::atomic::wait 方法来做到这一点。
不幸的是,虽然wait 已标准化,但wait_for 和wait_until 尚未标准化。这意味着我们不能在具有超时的原子变量上休眠。
无论如何,在 Windows 上使用 WaitOnAddress 和 Linux 上的 futex 系统调用在幕后实现对原子变量的睡眠。
解决上述问题(无法在超时的原子变量上休眠),我可以在 Windows 上将std::atomic 的内存地址传递给WaitOnAddress,它会(有点)在没有 UB 的情况下工作,因为函数以void*为参数,将std::atomic<type>转换为void*是有效的
在 Linux 上,是否可以将 std::atomic 与 futex 混合使用尚不清楚。 futex 获得 uint32_t* 或 int32_t*(取决于您阅读的手册),并将 std::atomic<u/int> 转换为 u/int* 是 UB。另一方面,手册说
uaddr 参数指向 futex 字。 在所有平台上, futexes 是四字节整数,必须在四字节上对齐 字节边界。在 futex 上执行的操作是 在 futex_op 参数中指定; val 是一个值,其含义 目的取决于 futex_op。
提示alignas(4) std::atomic<int> 应该可以工作,不管它是哪个整数类型,只要该类型的大小为 4 字节且对齐为 4。
另外,我看到很多地方实现了这种结合 atomics 和 futexes 的技巧,包括 boost 和 TBB。
那么,以非 UB 方式在具有超时的原子变量上休眠的最佳方法是什么? 我们是否必须使用 OS 原语实现自己的原子类才能正确实现它?
(存在混合原子和条件变量等解决方案,但不是最佳的)
【问题讨论】:
-
WaitOnAddress是条件变量的有限实现,原子性无关紧要。那么,与其使用原子,不如试试标准库中的经典条件变量? -
@facetus 吞吐量,主要是。
-
WaitOnAddress与原子无关,与std::condition_variable相比,我敢肯定不会给您带来任何好处。WaitOnAddress在语义上是一个条件变量,它只是将显式互斥锁隐藏在幕后。除此之外,它的作用完全相同。
标签: c++ linux c++20 stdatomic futex