跨平台实现 x86 的 pause 指令

8
什么是编写跨平台的x86暂停指令实现的最佳实践? 我计划在C ++ 11项目中的繁忙旋转循环中使用它。
如果我只使用gcc工具链,那么我可以使用_mm_pause内部函数。即使本机处理器不支持x86暂停指令,这个内部函数是否会执行正确的操作?我也希望我的代码能在clang / llvm工具链上运行。
我想一个备选方案可以使用“std :: this_thread :: sleep_for”,因为我正在使用C ++ 11。但我不确定如何检测处理器功能(支持暂停还是不支持)并回退到睡眠状态。
我正在使用cmake构建我的项目,并且将始终在同一台机器上构建和部署。因此,在编译期间检测处理器设置是可行的。
以下是一个示例实现(伪代码):
void pause() {
// Not sure how to detect if pause is available on the platform.
#if defined(USE_mm_pause)
  __asm__ ( "pause;" );
#else
  std::this_thread::sleep_for(std::chrono::seconds(0));
#endif
}

检测指令是否可用的方法是编写一个使用该指令的小程序,然后在编译过程中进行编译、链接和运行。如果该指令对于工具链和硬件来说是可接受的一部分,那么编译器将正常工作;否则,你将得到一个编译失败或者一个非法指令的SIGILL错误。 - Phil Miller
1
我更喜欢使用 __asm__ __volatile__("pause;");,这样GCC就不会在暂停期间重新排列内存访问。 - Casey
sleep_foryield 有任何关联吗?还是只是巧合?因为对于 sleep/yield,调度程序会处理您的时间片,而 nop 只是一个空操作。 - Red XIII
1
@RedXIII 这是一个问题吗?std::this_thread::sleep_for将运行睡眠命令,它只会使当前线程休眠,而不会安排另一个线程在核心上运行。对于yield,C++ 11具有std::this_thread::yield命令。这允许调度程序重新安排。 - Rajiv
1
使用<immintrin.h>中的_mm_pause()函数。它可以在所有主要编译器中使用,包括MSVC。请参见如何在64位C++代码中使用暂停汇编指令?。(有重复内容的倾向,可能会被关闭。) - Peter Cordes
1个回答

13

即使本机处理器不支持x86暂停指令,该特性是否仍然能够正常工作?

是的,暂停指令被编码为F3 90。对于不知道该指令的早期Pentium 4处理器,它将把它解码为:

  REP NOP

这只是一个普通的NOP指令,带有无用的前缀字节。处理器会等待一两个周期,然后继续执行,而不会以任何方式改变处理器状态。虽然您将无法获得使用PAUSE所带来的性能和功耗优势,但程序仍将按预期工作。

有趣的是: REP NOP即使在大约35年前发布的8086处理器上也是合法的。这就是我所谓的向后兼容性。


谢谢回答。这似乎是gcc的一个好解决方案。对于其他编译器,特别是clang的支持有什么评论吗? - Rajiv
我之前使用的是“xmmintrin.h”头文件。现在我已经切换到“x86intrin.h”。看起来它可以在gcc 4.3和clang 3.3.1上工作。 - Rajiv

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