写自定睡眠的正确方法

时间:2017-06-22 22:35:51

标签: c++ optimization

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

基本上,问题变成"写一个get_time和睡眠按照ROS时间进行缩放"?这样做不会改变代码库,只需要链接到自定义get_time和sleep。 get_time似乎完美无缺;但是,我一直无法让睡眠准确地运行。

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

  1. 线程调用睡眠
  2. Sleep会将解锁此线程(current_time + sleep_time)的时间添加到优先级队列中,然后等待条件变量。
  3. 一个单独的线程(让它称之为观察者)将不断循环并检查队列的顶部;如果prio队列的顶部>当前时间,然后它会在条件变量上发出notify_all然后弹出prio队列
  4. 然而,似乎观察者线程不够准确(我看到0~50ms的差异),这意味着睡眠调用有时使线程睡眠时间过长。我还明显地注意到模拟器中的滞后/锯齿状行为,如果我用睡眠替换睡眠(1000 * ms)。

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

    • 通过使用条件变量数组并根据时间分配它们来减少不必要的notify_all调用次数,如下所示:(ms / 100)%256。这个想法是一起关闭时间将共享相同的cv,因为它们可能实际上从notify_all唤醒。这使性能更差
    • 保持线程和prio_queue推送等,而是使用usleep。我发现usleep会使它工作得更好,这可能意味着互斥锁,锁定和推/弹操作不会导致显着的滞后量,这意味着它必须在条件变量部分

    代码: Watcher(这是在启动时运行)

    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();
    }
    

    任何帮助将不胜感激。

0 个答案:

没有答案