【发布时间】:2019-02-02 12:24:08
【问题描述】:
最近我发现由于未知原因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/
【问题讨论】:
-
当你放弃你的 CPU 量时,你不确定多久能取回它;您要求的时间只是一个提示。如果系统繁忙,你可能要等待任意长的时间。
-
休眠线程在某种程度上是一种反模式。你到底想在这里做什么?你想解决什么问题?另见:Windows 7: overshoot C++ std::this_thread::sleep_for
sleep_for在 Microsoft 的 CRT 中是基于系统时钟的,因此如果时钟发生变化,您可能会看到更长的睡眠时间。您确定“环境没有任何变化”吗? -
@Cody Gray♦ 这是一个非常有趣的链接。至少我知道其他人也遇到过同样的问题。
-
你得到的唯一保证是,只要你要求,线程就会休眠至少。它可能会睡得更久,而您没有保证“更长”的上限。
-
可能值得尝试在您的
main()顶部调用timeBeginPeriod(1),看看是否有任何改善。
标签: c++