【问题标题】:Spin wait C++11旋转等待 C++11
【发布时间】: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


【解决方案1】:

信号量确实是让写入器发出新数据信号的好选择,而读取器在数据准备好被使用时唤醒。但是,对于高性能场景,您应该考虑使用无锁队列,例如 Moody Camel 编写的队列。这样的队列允许写入者在不阻塞读取器的情况下添加新数据条目,并且读取器可以尽可能快地获取数据,而不会阻塞写入器。这样,如果数据可用,则可以以最大速度处理数据,否则不会消耗 CPU 资源。

【讨论】:

  • 我真的不需要队列,因此上面的构造。我想要比唤醒线程更快的东西,这就是为什么我想知道旋转等待以及实现它的最佳方法和潜在问题。
  • 嗯,我试图满足您对快速处理新数据的要求,并且无论您的自旋锁有多快,都可以在没有任何锁定的情况下运行得最快。
猜你喜欢
  • 2011-03-31
  • 2014-11-26
  • 2015-02-02
  • 1970-01-01
  • 1970-01-01
  • 2010-09-07
  • 2014-03-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多