高精度睡眠值约为5毫秒



我正在寻找一种解决方案,它可以为小值函数提供最准确的Sleep。我尝试了下面的代码来测试它:

#include <thread>
#include <chrono>
#include <functional>
#include <windows.h>
using ms = std::chrono::milliseconds;
using us = std::chrono::microseconds;
using ns = std::chrono::nanoseconds;
const int total_test = 100;
const int sleep_time = 1;
template <typename F,typename T>
long long sleep_soluion_tester(T desired_sleep_time, F func)
{
long long avg = 0.0;
for (int i = 0; i < total_test; i++)
{
auto before = std::chrono::steady_clock::now();
func(desired_sleep_time);
auto after = std::chrono::steady_clock::now();
avg += std::chrono::duration_cast<T>(after - before).count();
}
return avg / total_test;
};
template <typename F>
ms sleep_soluion_tester(int desired_sleep_time, F func)
{
ms avg = ms(0);
for (int i = 0; i < total_test; i++)
{
auto before = std::chrono::steady_clock::now();
func(desired_sleep_time);
auto after = std::chrono::steady_clock::now();
avg += std::chrono::duration_cast<ms>(after - before);
}
return avg / total_test;
};
int main()
{
auto sleep = [](auto time) {
std::this_thread::sleep_for(time);
};
ms sleep_test1 = static_cast<ms>(sleep_time);
us sleep_test2 = static_cast<us>(sleep_test1);
ns sleep_test3 = static_cast<ns>(sleep_test1);
std::cout << " desired sleep time: " << sleep_time << "msn";
std::cout << " using Sleep(desired sleep time) "<< sleep_soluion_tester(sleep_time, Sleep).count() << "msn";
std::cout << " using this_thread::sleep_for(ms) " << sleep_soluion_tester(sleep_test1,sleep) << "msn";
std::cout << " using this_thread::sleep_for(us) " << sleep_soluion_tester(sleep_test2,sleep) << "msn";
std::cout << " using this_thread::sleep_for(ns) " << sleep_soluion_tester(sleep_test3,sleep) << "msnn";

但似乎没有区别,即使传递的参数是1ms,它们也需要大约15毫秒才能完成。有没有一种方法可以提高睡眠函数的精度(或者一些可以提高精度的实现(?

我知道使用线程睡眠是一种不确定的方法,因为调度程序将决定何时恢复线程,但我想知道是否有任何方法可以提高精度?

好吧,在标准桌面操作系统上,不能保证睡得很短。

此外,你必须处理两个方面:

  1. 时间测量:如果测量方法的时间分辨率较低,则在测量时可能会得到完全错误的结果
  2. 睡眠功能本身的时间分辨率

然后,在非实时操作系统上,如Windows、MacOS和Linux,也可能发生进程/线程无法及时调度以提前唤醒的情况。如果睡眠时间更短,这种情况就更有可能发生。

因此,在Windows上,您可以使用WIN32 API并调整计时器周期,并将其设置为尽可能低的值:

timeBeginPeriod(1); // set period to 1 ms

在你的任务或程序结束时——根据文件——你必须用结束它

timeEndPeriod(1);

然后您可以使用WIN32睡眠功能:

Sleep(1); // (try to) sleep 1 ms

根据文件:

如果dwMilliseconds小于系统时钟的分辨率,则线程的睡眠时间可能小于指定的时间长度。如果dwMilliseconds大于一个刻度但小于两个刻度,则等待时间可以在一到两个刻度之间,依此类推。有关更多信息,请参阅此处:https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-sleep

在Linux上,您可以尝试nanosleep,请参阅https://man7.org/linux/man-pages/man2/nanosleep.2.html

对于时间测量,您可以分别在Windows上使用QueryPerformanceCounter函数和在Linux上使用clock_gettime函数。

这一切都不能保证你每次睡觉都能达到1毫秒的分辨率。但timeBeginPeriod是一种尝试,因为根据文档,默认计时器分辨率为15.6毫秒,这与您的测量值完全吻合。设置更高的分辨率,例如1毫秒,可能会对您有所帮助。对于需要";真实的";实时保证功能,这是不够的。为此,构建了实时操作系统。

最新更新