我想在线程内运行一个循环,每隔毫秒计算一些数据。但是我在睡眠功能方面遇到了麻烦。它睡得太久了。
我在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 ms\n", chrono::duration_cast<std::chrono::milliseconds>(Clock::now() - aTimeStart).count());
cin.get();
return 0;
}
打印出来:持续时间:5000毫秒 当我使用Sleep(1);
时,会打印相同的结果我希望持续时间 500 ms ,而不是5000 ms。我在这里做错了什么?
更新
我使用的是Visual Studio 2013.现在我安装了Visual Studio 2015,它的精美打印出:持续时间:500毫秒(有时是527毫秒)。
然而,这个sleep_for仍然不是很准确,所以我会寻找其他解决方案。
答案 0 :(得分:4)
流行操作系统使用的典型时间片长度超过1毫秒(比如大约20毫秒); sleep
设置您希望线程暂停多长时间的最小值。一旦你的线程变得可运行,操作系统将在下一次安排它时。
如果您需要这种级别的准确性,您需要一个实时操作系统,或者在您的线程上设置一个非常高的优先级(因此它可以抢占其他任何东西),或者在内核中编写代码,或者使用忙碌的等待。
但你真的需要每隔ms做一次计算吗?这种时序要求通常来自硬件。如果你稍后计算出来会出现什么问题?
答案 1 :(得分:0)
在Windows上,尝试timeBeginPeriod
:https://msdn.microsoft.com/en-us/library/windows/desktop/dd757624(v=vs.85).aspx
它增加了计时器分辨率。
答案 2 :(得分:0)
我在这里做错了什么?
尝试使用sleep
进行精确计时。
sleep(n)
不会暂停您的主题n
时间,然后立即继续。
sleep(n)
将线程控制权交还给调度程序,并指示在至少 n
时间过去之前您不想再进行控制。
现在,调度程序已经将线程处理时间划分为时间片,这些通常大约为25毫秒左右。这是最低限度,你可以期待睡眠运行。
sleep
对于这项工作来说简直就是错误的工具。 从不使用它进行精确调度。
答案 3 :(得分:0)
此线程相当陈旧,但也许有人仍然可以使用此代码。
它是为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速度更快,那么你的PC可能比这更准确。
这是典型的输出:
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