c++ - 定期检查条件而不阻塞

标签 c++ multithreading do-while

在我的项目中,函数 clipsUpdate 读取一些由 CLIPS 设置的事实,而不受我的 C++ 代码的干扰。基于读取的事实,clipsUpdate 调用所需的函数。

void updateClips(void)
{
     // read clipsAction

     switch(clipsAction)
     {
         case ActMove:
                 goToPosition (0, 0, clipsActionArg);
                 break;
     }
}

goToPosition函数中,向小车发送消息让小车移动到指定位置,然后使用while循环等待小车到达指定位置。

void goToPosition(float north, float east, float down)
{
     // Prepare and send the message

     do 
     {
          // Read new location information.
     }while(/*Specified position reached?*/)
}

问题是 updateClips 应该每 500 毫秒调用一次,当调用 goToPosition 函数时,执行会被阻塞,直到到达目标位置。在此等待期间,可能会发生需要车辆停下来的事情。因此,updateClips 无论如何都应该每 500 毫秒调用一次,并且如果 goToPosition 正在运行,它应该能够停止执行。

我试过如下使用线程,但它对我来说没有成功,而且我很难调试。我认为可以用更简单、更清洁的方式来完成。

case ActMove:
      std::thread t1(goToPosition, 0, 0, clipsActionArg);
      t1.detach();
      break;

我的问题是,如何在不阻止执行的情况下检查是否已到达目标位置,即不使用 while

最佳答案

您可能需要一个事件驱动模型。

在事件驱动模型中,您的主引擎是一个紧密循环,它读取事件、更新状态,然后等待更多事件。

有些事件是基于时间的,有些是基于输入的。

唯一允许阻塞主线程的代码是主循环,它会阻塞直到计时器命中或新事件到达。

它可能非常粗略地看起来像这样:

using namespace std::literals::chrono_literals;
void main_loop( engine_state* state ) {
  bool bContinue = true;
  while(bContinue) {
    update_ui(state);
    while(bContinue && process_message(state, 10ms)) {
      bContinue = update_state(state);
    }
    bContinue = update_state(state);
  }
}

update_ui如果需要,向用户提供反馈。

process_message(state, duration)查找要处理的消息,或等待 10 毫秒。如果它看到一条消息(如 goToPosition ),它会修改 state 以反射(reflect)该消息(例如,它可能会存储所需的目的地)。它不会阻塞,也不会花费很多时间。

如果duration中没有收到消息时间,它无论如何都会返回而不修改 state (我假设即使没有新的输入/消息出现,您也希望事情发生)。

update_state需要 state并进化它。 state可能有最后更新的时间戳; update_state然后将使“物理”反射(reflect)自上次以来的时间。或者进行任何其他更新。

重点是process_message不对状态起作用(它编码欲望),而update_state推进“现实”。

它返回 false如果主循环应该退出。

update_stateprocess_message 调用一次打电话。

updateClips每 500 毫秒调用一次可以编码为消息队列中的重复自动事件 process_message阅读。

void process_message( engine_state* state, std::chrono::milliseconds ms ) {
  auto start = std::chrono::high_resolution_clock::now();
  while (start + ms > std::chrono::high_resolution_clock::now()) {
    // engine_state::delayed is a priority_queue of timestamp/action
    // ordered by timestamp:
    while (!state->delayed.empty()) {
      auto stamp = state->delayed.front().stamp;
      if (stamp >= std::chrono::high_resolution_clock::now()) {
        auto f = state->queue.front().action;
        state->queue.pop();
        f(stamp, state);
      } else {
        break;
      }
    }
    //engine_state.queue is std::queue<std::function<void(engine_state*)>>
    if (!state->queue.empty()) {
      auto f = state->queue.front();
      state->queue.pop();
      f(state);
    }
  }
}

重复轮询是作为延迟操作实现的,作为其第一个操作,在该操作之后插入一个新的延迟操作 500 毫秒。我们传入操作应运行的时间。

可以将“正常”事件插入正常操作 queue , 这是 std::function<void(engine_state*)> 的序列并按顺序执行。

如果无事可做,上面的函数忙等待ms时间然后返回。在某些情况下,我们可能想去 sleep 。

这只是一个事件循环的草图。互联网上有很多很多。

关于c++ - 定期检查条件而不阻塞,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45600460/

相关文章:

javascript - 将项目插入数组的最佳性能方法?

java - 具有 3 个条件的 do-while 循环

java - 如何使用 do-while 循环再次检查用户输入?

java - 我正在使用 Java,但我的 while 语句不起作用

c++ - C/C++ 头文件中的函数是不行的吗?

c++ - 基于DCT的视频编码过程

c++ - 多线程传递参数

c - 增量同步原语

c++ - 为什么将无符号数左移 32 次不会产生零?

c++ - Visual Studio重构后的调试与差异搜索