C++ 编写自定义睡眠的正确方法

C++ 编写自定义睡眠的正确方法,c++,optimization,C++,Optimization,我目前正在为模拟器编写代码,以便与ROS时间同步 从本质上讲,问题变成了“写一个根据ROS时间缩放的get_时间和睡眠”?这样做将不允许更改代码库,只需要链接到定制的get_time和sleep获取时间似乎工作得很好;然而,我一直很难让睡眠准确地运行 我目前的设计是这样的(代码附在底部): 线程调用睡眠 Sleep将把解锁此线程的时间(当前时间+睡眠时间)添加到优先级队列中,然后等待条件变量 一个单独的线程(我们称之为watcher)将不断循环并检查队列的顶部;如果prio队列的顶部>当前时间,

我目前正在为模拟器编写代码,以便与ROS时间同步

从本质上讲,问题变成了“写一个根据ROS时间缩放的get_时间和睡眠”?这样做将不允许更改代码库,只需要链接到定制的get_time和sleep<代码>获取时间似乎工作得很好;然而,我一直很难让睡眠准确地运行

我目前的设计是这样的(代码附在底部):

  • 线程调用睡眠
  • Sleep将把解锁此线程的时间(当前时间+睡眠时间)添加到优先级队列中,然后等待条件变量
  • 一个单独的线程(我们称之为watcher)将不断循环并检查队列的顶部;如果prio队列的顶部>当前时间,则它将通知条件变量上的_all,然后弹出prio队列
  • 但是,似乎watcher线程不够精确(我看到0~50ms的差异),这意味着sleep调用有时会使线程睡眠时间过长。与使用usleep(1000*ms)代替睡眠相比,我还明显注意到模拟器中的延迟/锯齿行为

    不幸的是,我对这些类型的设计不是很有经验,我觉得有很多方法可以优化/重写它,使其运行更准确。 所以我的问题是,条件变量是正确的方法吗?我用对了吗?以下是我尝试过的一些事情:

    • 通过使用条件变量数组并根据时间分配它们,减少不必要的notify_all调用的数量,如:(ms/100)%256。他们的想法是,在一起的时间将共享同一份简历,因为他们很可能从“通知所有人”中醒来。这使得性能更差
    • 保持线程和优先级队列推送等,但使用usleep。我发现usleep将使其工作得更好,这可能意味着互斥、锁定和推/弹出操作不会造成明显的延迟,这意味着它必须位于条件变量部分

    代码: 监视程序(在启动时运行)

    void-watcher()
    {
    while(true)
    {
    usleep(1);
    {
    std::lock_guard lk(m_队列);
    if(prio_queue.empty())
    继续;
    if(get_time_in_ms()>=prio_queue.top())
    {
    cv.通知所有人();
    prio_queue.pop();
    }
    }
    }
    }
    
    睡眠

    void sleep(int-ms)
    {
    int wakeup=get_time_in_ms()+ms;
    {
    std::lock_guard lk(m_队列);
    优先级队列推送(唤醒);
    }
    std::唯一锁定lk(m_时间);
    cv.wait(lk,[wakeup]{return get_time_in_ms()>=wakeup;});
    lk.unlock();
    }
    

    任何帮助都将不胜感激

    睡眠时间只保证至少是你要求的时间量。从来都不能保证精确的睡眠。为了减少错误,您需要在RTOS上运行,但我不相信有任何系统能够准确、一致地保持精确的睡眠。也许引入1pps信号+中断是一个好方法,但这会增加一些恼人的硬件+软件开销。但我确实知道,操作系统的usleep比这个版本要好得多。它不需要完美;正如操作系统所做的一样,它的睡眠时间只保证至少是您请求的时间量。从来都不能保证精确的睡眠。为了减少错误,您需要在RTOS上运行,但我不相信有任何系统能够准确、一致地保持精确的睡眠。也许引入1pps信号+中断是一个好方法,但这会增加一些恼人的硬件+软件开销。但我确实知道,操作系统的usleep比这个版本要好得多。它不需要完美;就像操作系统如何做到这一点一样好
    void watcher()
    {
      while (true)
      {
        usleep(1);
        {
          std::lock_guard<std::mutex> lk(m_queue);
          if (prio_queue.empty())
            continue;
          if (get_time_in_ms() >= prio_queue.top())
          {
            cv.notify_all();
            prio_queue.pop();
          }
        }
      }
    }
    
    void sleep(int ms)
    {
      int wakeup = get_time_in_ms() + ms;
      {
        std::lock_guard<std::mutex> lk(m_queue);
        prio_queue.push(wakeup);
      }
      std::unique_lock<std::mutex> lk(m_time);
      cv.wait(lk, [wakeup] {return get_time_in_ms() >= wakeup;});
      lk.unlock();
    }