【发布时间】:2019-04-29 19:36:11
【问题描述】:
我有以下结构
struct info {
unsigned long a;
unsigned long b;
};
atomic <info> data;
由写入线程和读取线程使用。读者必须尽快对新值做出反应。为此,我在阅读器中实现了以下内容:
while (true) {
auto value = data.load();
// do some operations given these new values
}
此操作非常占用处理器资源。我选择了这种方法,因为我相信它比使用条件变量然后在数据更改时等待读取器线程被唤醒要快。此外,数据更新非常频繁,每秒数百次。有没有更好的方法来做到这一点,同时仍然具有最快的反应时间?
【问题讨论】:
-
我建议你同时实现它并比较速度和资源使用情况。
-
如果您使用的是 x86,您可能需要在自旋循环中使用
pause指令 (_mm_pause()) 以避免内存顺序错误推测管道在发生更改时刷新。而且还可以省电。 (顺便说一句,在多 GHz CPU 上,每秒数百次只是每百万个时钟周期更新一次,这非常简单。但您可能想检查data是否实际上与您看到的最后一个值不同。) -
无论如何,我认为这几乎是反应时间和 CPU 使用率之间的权衡;我认为旋转等待比操作系统辅助唤醒的延迟更低。在当前 x86 的内核模式下,有监视器/mwait 可以让 CPU 在更改到某个地址时唤醒。 (或即将推出的 Intel Tremont (atom) CPU 上的用户空间,umonitor / umwait)但这仍然意味着 CPU 不能做其他事情,它必须在等待事件而不是忙于等待时处于睡眠状态。
-
另外,请检查您的编译器是否真的将 2 成员结构视为无锁对象。如果
unsigned long是 8 字节类型,那么您有 16 字节的原子负载。在 x86-64 上,只有lock cmpxchg16b才有可能,而 gcc7 和更高版本则不能内联。您可以使用联合黑客仅旋转结构的一个成员吗? How can I implement ABA counter with c++11 CAS? -
繁忙的循环/自旋循环几乎总是错误的解决方案。
标签: c++ c++17 spinlock stdatomic spinwait