c++ - 在性能关键型软件 (Qt) 中使用定时器

标签 c++ performance qt timer robot

我正在开发一个应用程序,负责通过 UDP 连接移动和管理机器人。

应用程序需要:

  • 使用 SDL 读取操纵杆/用户输入。
  • 每 20 毫秒生成并向机器人发送一个控制数据包 (UDP)
  • 接收并解码来自机器人的响应数据包(~20 毫秒)。这是通过信号/槽机制实现的,不需要计时器。
  • 出于调试原因接收和处理机器人消息。这不受时间限制。
  • 定期更新用户界面,让用户了解机器人的状态(例如电池电压)。对于大多数情况,我还使用了 Qt 的信号/槽机制。
  • 如果 1 秒后未收到响应,则使用看门狗禁用机器人。当应用程序收到机器人数据包时(~20 毫秒)重置看门狗

目前,我已经实现了以上所有内容。但是,当激活看门狗或使用两个或多个 QTimer 对象时,应用程序无法定期发送数据包。该应用程序通常可以工作,但我不认为它是“生产就绪”的。我尝试使用计时器的精度标志(Qt::PreciseQt::CoarseQt::VeryCoarse),但是我仍然遇到问题。

注意事项:

  • 代码通常组织良好,代码库中没有“神对象”(大多数源文件长度少于 150 行,并且只创建必要的依赖项)。
  • 大多数时候,我使用QTimer::singleShot()(例如,我只会在当前数据包发送后发送下一个数据包)。

我们在哪里使用计时器:

  • 读取操纵杆输入(~50 毫秒,精确计时器)
  • 发送机器人数据包(~20 毫秒,精确计时器)
  • 更新 UI 的某些方面(约 500 毫秒,粗略计时器)
  • 更新自启用机器人以来耗时(~100 毫秒,精确计时器)
  • 实现看门狗(如果 1000 毫秒没有机器人响应,则将应用程序和机器人置于安全状态)
  • 注意:当我们收到来自机器人的响应数据包时(~20 毫秒),看门狗开始工作

对于将 QTimer 对象与性能关键代码一起使用,您有什么建议吗(欢迎提出任何想法)。请注意,我也曾尝试使用不同的线程,但这给我带来了更多问题,因为应用程序不会处于“同步”状态,因此无法有效控制我们测试过的机器人。

最佳答案

其实,我似乎低估了Qt的定时器和事件循环的性能。在我的系统上,事件循环周期平均大约 20k 纳秒加上调度排队函数调用的开销,间隔为 1 毫秒的计时器很少延迟,大多数超时是几千纳秒不到一毫秒。但它是一个高端系统,在嵌入式硬件上可能会差很多。

您应该花时间分析您的目标系统和 Qt 构建,以确定它是否确实可以足够快地运行,并根据这些测量结果调整您的时间安排以补偿系统延迟,从而使您的事件安排得更准时。

您一定要让计时器线程尽可能空闲,因为如果您通过 IO 或大量计算阻塞它,您的计时器将不准确。使用专用线程来安排工作,使用额外的工作线程来完成实际工作。您也可以尝试稍微调整一下线程优先级。

最坏的情况,寻找 3rd 方高性能事件循环实现或者创建你自己的,也可能是更快的信号机制。正如我在评论中已经提到的,Qt 的线程间排队信号非常慢,至少与间接函数调用之类的东西相比是这样。

最后但同样重要的是,如果您想每 N 个单位时间执行一次任务 X,则只有当任务 X 在您的系统上花费 N 个单位时间或更少时才有可能。您需要对每个任务以及同时运行的所有任务进行此考虑。并且为了得到准确的调度,你应该测量任务 X 花费了多长时间,如果小于它的频率,则在剩余时间内安排下一次执行,否则立即执行。

关于c++ - 在性能关键型软件 (Qt) 中使用定时器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32979661/

相关文章:

c# - foreach + break vs linq FirstOrDefault 性能差异

c++ - 替换 QDockWidget 的小部件而不删除以前的

c++ - 如何使用Qt检查文件夹是否可写

c++ - 如何将基数转换为序数

c++ - Xcode MongoDB Boost 导入 <angle>

performance - 即使设置了 PCE,用户模式下的 rdpmc 也不起作用

xna - 这个样本会产生垃圾吗?

linux - 在 Linux 上安装 qt

c++ - 如何应用注册表模式使 "select class depend on input"服从开闭原则?

c++ - 高于给定值的最小可表达值