Windows操作系统中(软实时)定时要求的限制

本文关键字:定时 操作系统 实时 Windows | 更新日期: 2023-09-27 18:13:52

在我工作的公司里,我们制造的机器是由运行在Windows操作系统上的软件控制的。c#应用程序与总线控制器通信(通过DLL)。总线控制器的正常运行时间为15ms。这意味着,我们从总线控制器获得系统中具有15ms心跳的实际传感器的更新(其中实时)。

现在,机器正在进化到下一代,我们得到了一个新的总线控制器,运行在1ms的节点上。既然每个人都意识到Windows不是一个实时操作系统,那么问题来了:我们应该把软件的控制部分转移到一个实时应用程序(在一个实时操作系统上,例如(软)PLC)上吗?

如果我们停留在windows平台上,我们不能保证响应。这本身并不一定是个问题;如果我们错过了几个总线周期(有一些故障),机器将会稍微慢一点(这是可以接受的)。

让我担心的部分是主机控制线程之间的线程同步,以及我们从实时控制器接收到的更新(每毫秒)。

我在哪里可以了解更多关于Windows/.NET c#在毫秒线程同步路径下的行为?我知道,例如Thread.Sleep(1)可以占用15毫秒,因为Windows是抢占其他任务,所以这如何反映当我同步两个线程与Monitor.PulseAll每毫秒?我能期待同样不可预测的行为吗?当我在Windows应用程序中移动到1ms的软实时需求时,这是在自找麻烦吗?

我希望有经验的人在线程的这些方面可以给出一些启示。如果我需要进一步澄清,尽管开枪吧。

Windows操作系统中(软实时)定时要求的限制

您的场景听起来像是kiosk模式/专用应用程序的候选。

在我工作的公司里,我们制造的机器是由运行在Windows操作系统上的软件控制的。

如果是这样,您可以配置机器,使您的低延迟I/O线程可以在线程和进程优先级最大化的专用核心上运行。此外,确保机器有足够的内核来处理缓冲线程以及处理传输中数据的任何其他线程。如果可能的话,缓冲区应该提前分配内存,以避免垃圾收集瓶颈。

@Aron的示例适用于数据完整性可能在一定程度上受到损害的情况。在音频中,由于多种原因,延迟在录制过程中影响很大,但对于纯粹的播放,数据丢失在一定程度上是可以接受的。我想这在你的情况下不是一个选项。

当然,Windows不是一个实时操作系统,但如果你把它用于一个专用的应用程序,你可以控制它的各个方面,可以关闭所有不相关的服务和后台进程。

我已经有相当数量的成功编写软件来监测UPS单元如何处理功率波动通过测量他们的功率补偿响应时间(免责声明:不用于商业目的)。由于每个样本要测量的数据非常小,因此GC没有问题,并且我们将预分配的内存块循环用于缓冲区。

一些有用的微优化:

  • 使用不可变structs轮询I/O数据
  • 优化数据结构,使其与内存分配良好配合。
  • 优化处理算法以最小化CPU缓存丢失。
  • 使用优化的缓冲区类来保存传输中的数据。
  • 使用MonitorInterlocked类进行同步
  • 使用不安全代码与(void*)以各种方式轻松访问缓冲区数组,以减少处理时间。尽量少使用MarshalBuffer.BlockCopy .

最后,您可以采用DDK方式,编写一个小驱动程序。尽管与主题无关,但DFMirage是一个很好的视频驱动程序示例,它为差分屏幕捕获提供了基于事件和轮询模型,以便消费者应用程序可以根据系统负载动态选择。

对于Thread。考虑到你的能量消耗极限,你可以尽量少睡。排除冗余进程后,Thread.Sleep(1)应该不会像您想象的那么糟糕。试试下面的方法,看看你会得到什么。请注意,这是在SO编辑器中编写的,所以我可能犯了错误。

Thread.CurrentThread.Priority = ThreadPriority.Highest;
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.RealTime;
var ticks = 0L;
var iteration = 0D;
var timer = new Stopwatch();
do
{
    iteration++;
    timer.Restart();
    Thread.Sleep(1);
    timer.Stop();
    ticks += timer.Elapsed.Ticks;
    if (Console.KeyAvailable) { if (Console.ReadKey(true).Key == ConsoleKey.Escape) { break; } }
    Console.WriteLine("Elapsed (ms): Last Iteration = {0:N2}, Average = {1:N2}.", timer.Elapsed.TotalMilliseconds, TimeSpan.FromTicks((long) (ticks / iteration)).TotalMilliseconds);
}
while (true);
Console.WriteLine();
Console.WriteLine();
Console.Write("Press any key to continue...");
Console.ReadKey(true);

考虑实际问题本身,在1ms内处理数据非常容易。当考虑录音时,作为一个类似的问题,你可能会在如何实现你的目标中找到一些灵感。

请记住

  • 即使是适度的设置也可以达到44.1kHz@16bit每通道采样率(约22微秒或不到目标的百分之一)。
  • 使用ASIO可以实现低于10ms的延迟
  • 大多数实现高采样率的方法将通过增加缓冲区大小和批量向系统发送数据来工作
  • 为了获得最佳吞吐量,不要使用线程。你DMA和中断回调你的处理循环。

考虑到声卡通常可以实现您的目标,您可能有机会。