std::sleep_for在Windows 10上的不可预测行为
Unpredictable behaviour of std::sleep_for on Windows 10
最近我发现,由于未知原因,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库的定时器,得到了相同的结果。无论我做什么,我都不能让线程睡眠少于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的评论创建的。他建议在main()
的开头尝试timeBeginPeriod(1)
。成功了!我创建了一个程序的修改,它运行速度快了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
谢谢Jeremy!
p.S。增加定时器频率有其代价:https://randomascii.wordpress.com/2013/07/08/windows-timer-resolution-megawatts-wasted/
查看文档:
阻止当前线程执行至少指定的sleep_duration。由于调度或资源争用延迟,此函数可能会阻塞超过sleep_duration的时间。
- 不可预测的C++睡眠/等待行为
- 超过 N 时出现不可预测的位移结果
- DirectShow CSourceStream::FillBuffer 暂停和查找后对第一帧的不可预测的调用数
- 多线程文件 IO 程序在线程数增加时行为不可预测
- 使用 std::find 查找从二进制文件中读取的字符并转换为 std::vector 中的 std::string<string> 会产生这种不可预测的行为?
- std::sleep_for在Windows 10上的不可预测行为
- 不可预测的文件描述符泄漏
- 循环程序的行为是不可预测的
- C++中不可预测的输出
- 当来自外部库的线程不可预测地崩溃我的应用程序时,我该怎么办
- 不可预测的伪RNG
- C++ 自定义运算符(+=) 的行为方式不可预测
- 如何优化间接基数排序?(又名如何优化不可预测的内存访问模式)
- 修复不可预测的崩溃
- 不可预测的指针行为
- wxWidgets 不可预测的 Seg 故障
- 当 cin.getline() 的第二个参数大于数组长度时,不可预测的字符串长度
- 子表达式求值顺序的不可预测性
- 将QString转换为const-char*时的不可预测的运行时行为
- Qt. QDateTime具有时区和附加秒的不可预测行为