使用sleep_for每毫秒运行一次循环

时间:2015-09-26 10:24:20

标签: c++ c++11

我想在线程内运行一个循环,每隔毫秒计算一些数据。但是我在睡眠功能方面遇到了麻烦。它睡得太久了。

我在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仍然不是很准确,所以我会寻找其他解决方案。

4 个答案:

答案 0 :(得分:4)

流行操作系统使用的典型时间片长度超过1毫秒(比如大约20毫秒); sleep设置您希望线程暂停多长时间的最小值。一旦你的线程变得可运行,操作系统将在下一次安排它时。

如果您需要这种级别的准确性,您需要一个实时操作系统,或者在您的线程上设置一个非常高的优先级(因此它可以抢占其他任何东西),或者在内核中编写代码,或者使用忙碌的等待。

但你真的需要每隔ms做一次计算吗?这种时序要求通常来自硬件。如果你稍后计算出来会出现什么问题?

答案 1 :(得分:0)

在Windows上,尝试timeBeginPeriodhttps://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