【问题标题】:Enforcing real-time constraint in multi-threaded context在多线程上下文中实施实时约束
【发布时间】:2013-05-28 15:15:31
【问题描述】:

我目前正在为一个必须实时轮询、处理和显示数据(带有绘图)的程序用 C++ 开发 GUI。

我正在努力解决的部分是代码,它在一个单独的线程中运行,它实际上从一些外部硬件轮询数据,然后对其进行处理。我希望以固定周期(即两次调用之间的 1/20 秒)定期调用执行此工作的函数。

我真的不知道这是否可能以及如何强制执行必须定期调用该函数的事实,即每秒 20 次...

在阅读了一些关于实时编程的知识后,并根据我在游戏开发和主游戏循环的概念方面所学到的知识,我的第一种方法是使用一个循环,它会根据如何调整执行时间轮询 + 处理花费了很多时间:

 while(running){
     //Let's assume this function get the time elapsed since
     //the program started
     int start = get_current_time_millisecond();

     //Retrieve the data from the hardware
     pollData();

     //Process the data retrieved
     processData();

     //Queue the data wherever it is needed:
     //- plotting widget of the GUI
     //- recording object
     dispatchProcessedData();

     int elapsed = get_current_time_millisecond() - start;
     int remaining = 50 - elapsed;

     if(remaining > 0){
         sleep(remaining);
     }
 }

但这似乎有缺陷,因为如果在一次迭代中经过的时间大于我想要坚持的时间,它可能会导致漂移问题。

这可能是因为计算花费了太多时间(我对此深表怀疑,但我的经验不足以确定,分析可以帮助消除这个问题,或者至少确定代码可能需要很多时间),但我也想知道我运行多个线程的事实是否会由于线程调度而导致相同的问题(再次,我对多线程很陌生,我可能完全错了)。

所以我想问一下:

  • 是否可以通过实时编程(在多线程上下文中,如果相关)强制实施这样的约束以及如何实施?
  • 在设计此类代码时应遵循哪些主要准则?

(如果我错过了关于该主题的明显/容易找到的文档,我深表歉意)

谢谢!

【问题讨论】:

  • 如果你想对你的进程进行如此严格的调度,你几乎需要一个实时操作系统。大多数桌面操作系统的调度会更加灵活(尽管您可以鼓励它们按照您的意愿行事)。
  • @MarkB 老实说,我有点害怕。不幸的是,这并不意味着要在 RTOS 上运行。那么,我是否应该简单地放弃并保持这种方式(从而放弃我每秒 20 个数据并让程序“尽其所能”)?
  • 您是否可以为此访问 C++11?听起来Chrono 是您所需要的。但也许我没有做对,这个 tldr 是否正确? “创建单独的线程来轮询数据并每秒精确存储/处理 20 次”
  • @EdwardA 是的,我可以访问 C++11(感谢您指出 Chrono),是的,这个 tl;dr 是准确的。

标签: c++ multithreading real-time


【解决方案1】:

除非你有一个外部的、可靠的中断源,否则很难强制执行这样的约束。

我相信您可以在消费者操作系统上做的最接近的事情是:

  • 确保您使用的是实时内核(例如,使用 Linux 的 RT 补丁)以最大限度地减少时序变化。
  • 将您的轮询线程设置为尽可能高的优先级。
  • 仅在您的轮询线程中进行轮询和分派,将任何处理留给较低优先级的线程,以便计算不会影响您的轮询。
  • 使用高精度计时器(在 Linux 上,您可以使用纳秒而不是毫秒)来减少误差范围。
  • 使用无锁队列在轮询线程和处理线程之间进行通信,这样您就不必支付轮询线程中互斥锁的成本(但每秒只有 20 个样本,这可能无关紧要)。

至少这就是我们为我们的产品所做的,它在 400 MHz CPU 上以 100Hz (10ms) 的频率进行轮询。你永远不会完全摆脱这种漂移,但它是非常少的。

【讨论】:

  • 感谢这些提示!我认为这实际上可以帮助我用我所拥有的东西来为此做出正确的设计(我不能真正使用 RTOS,我被 Windows 困住了)
  • 卡在 Windows 上 - 嗯,这让事情变得更难了。 Windows 以“奇怪”的方式安排进程,显然很难以固定的时间间隔可靠地运行。一个提示 - 当您确实捕获数据项时,可能也需要注意一天中的精确时间并将其与数据本身打包在一起。这样,如有必要,您可以稍后(可能在绘制数据时)进行一些插值以消除调度可变性。这需要一些数学知识,但是有很多库会有所帮助。如果您将 C++ 编译为 .NET 应用程序,请不要期望有太大的稳定性。
【解决方案2】:

正如@Mark 建议的那样,最好使用实时操作系统。

如果一种“软”RT足够好,您应该创建一个具有高优先级的线程(例如,在 Linux 中使用调度类实时 FIFO 或类似的东西)并设置一个循环定时器,它会唤醒你的线程,例如通过信号量。

此外,将绘图与处理分离是一个好主意。

【讨论】:

  • 确实,这就是我对 dispatchProcessedData() 的意思,它将处理后的数据排队到绘图和记录“函数”中。
  • 好的,但是,您应该分派绘图:通常处理对时间要求更高,应该由计时器驱动。
  • 明白了!感谢您对此的见解!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-12-14
  • 2021-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多