【发布时间】:2013-11-04 23:55:33
【问题描述】:
编写 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
}
【问题讨论】:
-
检测指令可用性的方法是编写一个使用它的小程序,然后在编译过程中编译、链接和运行该程序。要么它是工具链和硬件可接受的 ISA 部分,要么你得到一个失败的编译器或一个非法指令的
SIGILL。 -
我更喜欢
__asm__ __volatile__("pause;");,这样 GCC 就不会在暂停期间重新排序内存访问。 -
sleep_for是否与 yield 有任何关系,或者这是巧合,至于 sleep/yield 调度程序会处理您的时间片,而 nop 只是一个 nop。 -
@RedXIII 这是个问题吗? std::this_thread::sleep_for 将运行 sleep 命令,该命令只会使当前线程进入睡眠状态,但不会安排另一个线程在核心上运行。对于 yield,C++ 11 有 std::this_thread::yield 命令。这使调度程序有机会重新调度。
-
使用
_mm_pause()来自<immintrin.h>。它可移植到包括 MSVC 在内的所有主要编译器。见How do you use the pause assembly instruction in 64-bit C++ code?。 (试图将其作为副本关闭。)