我正在寻找解决方案,这将给我最准确的睡眠一个函数的小值。我尝试了下面的代码来测试它:
#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 << "ms\n";
std::cout << " using Sleep(desired sleep time) "<< sleep_soluion_tester(sleep_time, Sleep).count() << "ms\n";
std::cout << " using this_thread::sleep_for(ms) " << sleep_soluion_tester(sleep_test1,sleep) << "ms\n";
std::cout << " using this_thread::sleep_for(us) " << sleep_soluion_tester(sleep_test2,sleep) << "ms\n";
std::cout << " using this_thread::sleep_for(ns) " << sleep_soluion_tester(sleep_test3,sleep) << "ms\n\n";但是似乎没有什么区别,即使传递的参数是1ms,它们都需要大约15毫秒才能完成。是否有一种方法可以提高休眠函数的精度(或者某些实现会导致更高的精度)?
我知道使用线程睡眠是一种不确定的方法,因为调度程序将决定什么时候线程将被恢复,但是我想知道是否有任何提高精度的方法?
发布于 2022-10-05 17:03:37
好吧,在标准的桌面操作系统上,睡眠时间很短是不能保证的。
此外,您还必须处理两个方面:
然后,在非实时操作系统(如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上,您可以尝试使用纳米睡眠,请参阅https://man7.org/linux/man-pages/man2/nanosleep.2.html
对于时间测量,您可以分别在QueryPerformanceCounter上和clock_gettime上使用Linux上的clock_gettime函数。
这些都不能保证你每次睡觉时都能达到1毫秒的分辨率。但是timeBeginPeriod是一种尝试,因为根据文档,默认的定时器分辨率是15,6ms,这完全符合您的测量标准。设置一个更高的分辨率,例如,1毫秒可能会帮助你。对于需要“真实”实时保证功能的任务来说,这是不够的。为此,构建了实时OSes。
https://stackoverflow.com/questions/73963381
复制相似问题