使用具有性能关键软件(Qt)的计时器

时间:2015-10-06 21:00:36

标签: c++ performance qt timer robot

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

应用程序需要:

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

目前,我已经实施了以上所有方面。但是,当监视器被激活或使用两个或更多QTimer个对象时,应用程序无法定期发送数据包。该应用程序通常可以工作,但我不认为它“生产就绪”。我曾尝试使用计时器的精确标记(Qt::PreciseQt::CoarseQt::VeryCoarse),但我仍遇到问题。

备注:

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

我们使用计时器的地方:

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

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

1 个答案:

答案 0 :(得分:4)

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

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

您应该尽可能保持计时器线程免费,因为如果您通过IO或大量计算阻止它,您的计时器将不准确。使用专用线程来安排工作和额外的工作线程来完成实际工作。您也可以尝试使用线程优先级。

最糟糕的情况是,寻找第三方高性能事件循环实现或创建您自己的,也可能是更快的信号机制。正如我在评论中已经提到的,Qt的线程间排队信号非常慢,至少与间接函数调用相比。

最后但并非最不重要的一点是,如果您希望每N个单位执行一次任务X,那么只有当任务X在您的系统上花费N个单位时间或更少时才能执行。您需要对每个任务以及所有并发运行的任务进行考虑。并且为了获得准确的调度,您应该测量任务X花费的时间,如果小于其频率,则在剩余的时间内安排下一次执行,否则立即执行。