最近我发现,由于未知原因,std::this_thread::sleep_for
可以睡超过预期的10倍。这不只是一个或几个偶然的延迟,但可以持续数分钟,影响也非常std::condition_variable::wait_for
显着的效果。
这里是我的代码:
#include <thread>
#include <iostream>
#include <chrono>
using namespace std;
int main(int argc, char const *argv[])
{
unsigned t = 0;
auto start = ::std::chrono::steady_clock::now();
for(unsigned i = 0; i < 100; ++i) {
::std::this_thread::sleep_for(chrono::milliseconds(1));
t ^= i; // prevent overeager optimization
}
auto stop = ::std::chrono::steady_clock::now();
auto elapsed = ::std::chrono::duration_cast<::std::chrono::milliseconds>(stop - start);
::std::cout << elapsed.count() << "\n";
::std::cerr << t << "\n";
return 0;
}
我与Visual Studio命令行工具编译的具体步骤如下:
cl /EHsc /std:c++17 /O2 sleep_for.cpp
当我执行它,结果是有时接近150,有时到1500执行之间,没有环境的变化。可能是什么这样的效果的原因是什么?
更新1.它看起来这是一个操作系统的问题。除了std::thread::sleep_for
和std::condition_variable::wait_until
,我也试过定时器基于uvw library,具有相同的结果。无论我做什么,我不能让一个线程睡眠时间少于15毫秒。这种效果是在系统启动之后很明显的,而且比它显得更加难得。
摘要。有些人建议:阅读文档!他们警告过你! std::this_thread::sleep_for
可能不稳定!但在另一方面,根据该文件,并没有什么错的,如果它工作更稳定,一个只需要知道如何做到这一点。杰里米Friesner提出了一个解决方案,我已经测试它和它的工作,呈现出10倍更好的性能和良好的稳定性平均值。是否使用std::this_thread::sleep_for
以及如何做到这一点,你deside。我肯定会建议不要使用它,如果你正在开发一个救生设备等,但在许多情况下,它可能是非常有用的。
一篇好文章,讨论提高稳定性和分辨率的价格:https://randomascii.wordpress.com/2013/07/08/windows-timer-resolution-megawatts-wasted/
阻塞当前线程的至少指定sleep_duration执行。此功能可以阻止超过因调度或资源争用延迟sleep_duration更长。
这个答案是从杰里米Friesner的评论创建。他建议在timeBeginPeriod(1)
的开始尝试main()
。这工作了!我创建的程序的修改,它运行快10倍。下面是代码:
#include <thread>
#include <iostream>
#include <chrono>
#include <windows.h>
using namespace std;
int main(int argc, char const *argv[])
{
timeBeginPeriod(1);
unsigned t = 0;
auto start = ::std::chrono::steady_clock::now();
for(unsigned i = 0; i < 100; ++i) {
::std::this_thread::sleep_for(chrono::milliseconds(1));
t ^= i; // prevent overeager optimization
}
auto stop = ::std::chrono::steady_clock::now();
auto elapsed = ::std::chrono::duration_cast<::std::chrono::milliseconds>(stop - start);
::std::cout << elapsed.count() << "\n";
::std::cerr << t << "\n";
return 0;
}
它可以使用以下命令进行编译:
cl /EHsc /std:c++17 /O2 sleep_for.cpp winmm.lib
谢谢,杰里米!
附:增加计时器频率有它的价格:https://randomascii.wordpress.com/2013/07/08/windows-timer-resolution-megawatts-wasted/