使用sleep_for每毫秒运行一次循环
Run loop every millisecond with sleep_for
我想在线程内运行一个循环,每毫秒计算一些数据。但是我的睡眠功能有问题。它睡得太久了。
我在visual studio中创建了一个基本的控制台应用程序:#include <windows.h>
#include <iostream>
#include <chrono>
#include <thread>
using namespace std;
typedef std::chrono::high_resolution_clock Clock;
int _tmain(int argc, _TCHAR* argv[])
{
int iIdx = 0;
bool bRun = true;
auto aTimeStart = Clock::now();
while (bRun){
iIdx++;
if (iIdx >= 500) bRun = false;
//Sleep(1);
this_thread::sleep_for(chrono::microseconds(10));
}
printf("Duration: %i msn", chrono::duration_cast<std::chrono::milliseconds>(Clock::now() - aTimeStart).count());
cin.get();
return 0;
}
打印结果:持续时间:5000 ms当我使用Sleep(1);
时,输出相同的结果我希望持续时间是500 ms,而不是5000 ms。我哪里做错了?
更新:
我使用的是Visual Studio 2013。现在我已经安装了Visual Studio 2015,它的精细打印出来:持续时间:500毫秒(有时是527毫秒)。
然而,这个sleep_for仍然不是很准确,所以我将寻找其他解决方案。
流行操作系统使用的典型时间片远长于1ms(比如20ms左右);sleep
设置了您希望线程挂起的最小时间,而不是最大值。一旦你的线程变得可运行,下一次调度它的时间就由操作系统决定了。
如果你需要这种级别的精度,你要么需要一个实时的操作系统,或者在你的线程上设置一个非常高的优先级(这样它就可以抢占几乎任何其他东西),或者在内核中编写代码,或者使用一个繁忙的等待。
但是你真的需要每毫秒计算一次吗?这种时序要求通常来自硬件。如果稍后再进行计算,会出现什么问题?
在Windows上,尝试timeBeginPeriod
: https://msdn.microsoft.com/en-us/library/windows/desktop/dd757624(v=vs.85).aspx
我在这里做错了什么?
尝试使用sleep
进行精确计时。
sleep(n)
不会在n
时间内暂停线程,然后立即继续。
sleep(n)
将线程的控制权交还给调度器,并指出在至少 n
时间过去之前,您不希望控制权交还给调度器。
sleep
对于这项工作来说是一个错误的工具。永远不要使用它来精确调度。
这个线程相当老了,但是也许有人仍然可以使用这个代码。
它是为c++ 11编写的,我在Ubuntu 15.04上测试了它。
class MillisecondPerLoop
{
public:
void do_loop(uint32_t loops)
{
int32_t time_to_wait = 0;
next_clock = ((get_current_clock_ns() / one_ms_in_ns) * one_ms_in_ns);
for (uint32_t loop = 0; loop < loops; ++loop)
{
on_tick();
// Assume on_tick takes less than 1 ms to run
// calculate the next tick time and time to wait from now until that time
time_to_wait = calc_time_to_wait();
// check if we're already past the 1ms time interval
if (time_to_wait > 0)
{
// wait that many ns
std::this_thread::sleep_for(std::chrono::nanoseconds(time_to_wait));
}
++m_tick;
}
}
private:
void on_tick()
{
// TEST only: simulate the work done in every tick
// by waiting a random amount of time
std::this_thread::sleep_for(std::chrono::microseconds(distribution(generator)));
}
uint32_t get_current_clock_ns()
{
return std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::system_clock::now().time_since_epoch()).count();
}
int32_t calc_time_to_wait()
{
next_clock += one_ms_in_ns;
return next_clock - get_current_clock_ns();
}
static constexpr uint32_t one_ms_in_ns = 1000000L;
uint32_t m_tick;
uint32_t next_clock;
};
典型的运行显示了一个非常精确的1ms循环,误差为1- 3微秒。如果你的电脑有更快的CPU,可能会比这更准确。
典型输出:
One Second Loops:
Avg (ns) ms err(ms)
[ 0] 999703 0.9997 0.0003
[ 1] 999888 0.9999 0.0001
[ 2] 999781 0.9998 0.0002
[ 3] 999896 0.9999 0.0001
[ 4] 999772 0.9998 0.0002
[ 5] 999759 0.9998 0.0002
[ 6] 999879 0.9999 0.0001
[ 7] 999915 0.9999 0.0001
[ 8] 1000043 1.0000 -0.0000
[ 9] 999675 0.9997 0.0003
[10] 1000120 1.0001 -0.0001
[11] 999606 0.9996 0.0004
[12] 999714 0.9997 0.0003
[13] 1000171 1.0002 -0.0002
[14] 999670 0.9997 0.0003
[15] 999832 0.9998 0.0002
[16] 999812 0.9998 0.0002
[17] 999868 0.9999 0.0001
[18] 1000096 1.0001 -0.0001
[19] 999665 0.9997 0.0003
Expected total time: 20.0000ms
Actual total time : 19.9969ms
我有一个更详细的写在这里:https://arrizza.org/wiki/index.php/One_Millisecond_Loop
- 循环中的条件:为什么每次都调用strlen(),而vector.size()只调用一次
- (C++)虽然循环一次不起作用,但我引入了多个变量
- 花括号使循环运行一次?
- 从子菜单返回后,正确的输入至少进入验证循环一次
- foor 循环的最后一次迭代中的指针更改
- 有没有办法在循环中的条件至少满足一次时运行语句?
- 循环中本地对象的析构函数是否保证在下一次迭代之前被调用?
- For循环在cpp中仅执行一次
- 将一副牌循环100次(一副牌)
- 如何强制循环执行另一次迭代到零并关闭循环
- (C++)for循环中的空初始语句是否保存所有编译器中变量的上一次初始化
- 当使用文件中的getline时,循环仅循环一次
- Arduino循环一次
- 在一个文件中循环一次,将行读取到添加到数组中的对象中
- 程序只循环一次
- 每 10 秒循环一次
- 每 'x' ms 重复循环一次
- 为什么这个单词排序程序只循环一次?
- 如何在c++中循环一次要求输入的switch-case语句?
- 通过只循环一次来组合c++标准算法