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

C# Windows操作系统中(软实时)计时要求的限制,c#,windows,multithreading,real-time,C#,Windows,Multithreading,Real Time,在我工作的公司里,我们制造的机器由运行在Windows操作系统上的软件控制。C#应用程序与总线控制器通信(通过DLL)。总线控制器的运行时间为15ms。这意味着,我们从总线控制器(实时)获取系统中实际传感器的更新,心跳为15毫秒 现在,这些机器正在发展成为下一代,我们在那里得到了一个新的总线控制器,它以1ms的速度运行。由于每个人都意识到Windows不是实时操作系统,因此出现了一个问题:我们是否应该将软件的控制部分移动到实时应用程序(在实时操作系统上,例如(软)PLC上) 如果我们停留在win

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

现在,这些机器正在发展成为下一代,我们在那里得到了一个新的总线控制器,它以1ms的速度运行。由于每个人都意识到Windows不是实时操作系统,因此出现了一个问题:我们是否应该将软件的控制部分移动到实时应用程序(在实时操作系统上,例如(软)PLC上)

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

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

我在哪里可以进一步了解Windows/.NET C#在以毫秒为单位执行线程同步时的行为?我知道,例如
Thread.Sleep(1)
可能需要15毫秒,因为Windows正在抢占其他任务,所以当我每毫秒使用
Monitor.pulsell
在两个线程之间进行同步时,这是如何反映的?我能期待同样不可预测的行为吗?当我进入Windows应用程序中1ms的软实时要求时,这是自找麻烦吗


我希望在线程的这些方面有经验的人能对此有所启发。如果我需要进一步澄清,那就开枪吧

想想实际问题本身,以1ms的速度处理数据非常容易。当考虑录音时,作为一个类似的(双关语不是有意的)问题,你可能会在如何实现你的目标中找到一些灵感

记住

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

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

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

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

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

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

当然,Windows并非设计为实时操作系统,但如果您将其用于专用应用程序,您可以控制其各个方面,并可以关闭所有不相关的服务和后台进程

我已经成功地编写了大量软件,通过测量功率补偿响应时间来监控UPS设备如何应对功率波动(免责声明:但并非出于商业目的)。由于每个样本要测量的数据非常小,GC没有问题,我们循环预分配的内存块以获得缓冲区

一些微优化派上了用场:

  • 使用不可变的
    structs
    轮询I/O数据
  • 优化数据结构以更好地处理内存分配
  • 优化处理算法以最小化CPU缓存未命中
  • 使用优化的缓冲区类保存传输中的数据
  • 使用
    监视器
    联锁
    类进行同步
  • 使用带有
    (void*)
    的不安全代码,以各种方式轻松访问缓冲区阵列,以减少处理时间。将
    封送
    缓冲区的使用降至最低。块拷贝
最后,您可以按照DDK的方式编写一个小驱动程序。这是一个很好的视频驱动程序示例,它为差异屏幕捕获提供了基于事件的模型和轮询模型,以便消费者应用程序可以根据系统负载动态选择

至于线程睡眠,考虑到你的能量消耗极限,你可以尽量少用它。由于消除了冗余进程,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);

您使用的是与您的计算机链接的单独计算机,还是使用集成到您的计算机中的内置处理器(“windows计算机”)@erstwhileii该计算机包含一组计算机,其中1台计算机是“systemPC”,这是一台在windows 7 embedded上运行的PC。这台电脑连接到运行实时操作系统的总线控制器(实际上它只是同一台计算机上的一个PCI express卡)。Windows操作系统还有一些“实时扩展”,可能对您的探索很有用。@YuvalItzchakov,已经读过thx文章了,我怀疑你的第一个瓶颈是GC,而不是操作系统。恐怕任何GC都会