c++ - Windows 10 上 std::sleep_for 的不可预测行为
问题描述
最近我发现,不知什么原因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
可能不稳定!但另一方面,根据文档,如果它工作得更稳定并没有错,只需要知道如何实现它。Jeremy Friesner 提出了一个解决方案,我已经对其进行了测试,结果显示出 10 倍的性能提升和良好的平均稳定性。是否使用std::this_thread::sleep_for
以及如何使用,您决定。如果您正在开发救生设备等,我绝对不建议使用它。但在许多情况下它可能非常有用。
一篇很好的文章,讨论了提高稳定性和分辨率的代价: https ://randomascii.wordpress.com/2013/07/08/windows-timer-resolution-megawatts-wasted/
解决方案
这个答案是根据 Jeremy 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
谢谢,杰里米!
PS增加定时器频率是有代价的: https ://randomascii.wordpress.com/2013/07/08/windows-timer-resolution-megawatts-wasted/
推荐阅读
- laravel - 使用传递多个值
- xamarin - ReceiveMemoryWarning 如果打开 pdf (mupdf-library)
- php - 无论我做什么,作曲家自动加载都不起作用
- php - Simplepie 不显示 RSS 提要
- angular - ngx-perfect-scrollbar 显示隐藏页脚
- c++ - 如何在 C++ 中的 lambda 函数中传递同名的局部变量和参数(使用 this 关键字)?
- reactjs - 在Material-Table中重新排序后是否可以获得当前页面数据?
- sql - 如何在plsql函数中查找包含字符串的行
- linux-kernel - 是否可以“拦截”进程的读/写?
- reinforcement-learning - RL Card Game DQN 上的预测输出为 NaN