好的,这个标题可能含糊不清,但请允许我解释一下。
我正在处理一个大型列表,数百条消息将作为字节数组发送到CAN总线。这些消息中的每一个都有一个Interval属性,详细说明了必须发送消息的频率(以毫秒为单位)。但我会回过头来看。
所以我有一个帖子。线程循环遍历这个巨大的消息列表,直到停止,身体大致如下:
Stopwatch timer = new Stopwatch();
sw.Start();
while(!ShouldStop)
{
foreach(Message msg in list)
{
if(msg.IsReadyToSend(timer)) msg.Send();
}
}
这很有效,在表达Message对象方面具有非凡的准确性。间隔。但是,它占用了整个CPU。问题在于,由于大量的消息和CAN总线的性质,在线程发送另一条消息之前通常不到半毫秒。永远不会出现线程能够睡眠超过15毫秒的情况。
我想弄清楚的是,是否有办法做到这一点,允许线程暂时阻塞或屈服,允许处理器休眠并节省一些周期。如果我尝试将工作分成每个消息的一个帖子,我会得到任何准确性吗?有没有其他方法可以做到这一点,我没有看到?
编辑:可能值得一提的是Message的Interval属性并不是绝对的。只要线程继续发出消息,接收器应该很高兴,但是如果线程经常休眠25分钟,因为更高优先级的线程窃取其时间片,它可能会引发接收器的红色标志。答案 0 :(得分:3)
根据更新的要求,Sleep(0)
的默认设置很可能就足够了 - 消息可能会以小突发发送,但听起来还可以。使用多媒体计时器可能会使爆发不太明显。建立对消息接收者的更多容忍可能是更好的方法(如果可能的话)。
如果你需要很好的毫秒级精度且保证良好 - Windows上的C#不是最佳选择 - 可能需要单独的硬件(甚至是Adruino),或至少是C#的低级代码。
Windows不是RT操作系统,因此您无法真正获得亚毫秒精度。
如果你需要亚毫秒的精度,那么繁忙的循环(可能在高pri线程上)是常用的方法。
您可以尝试使用多媒体计时器(示例 - Multimedia timer interrupts in C# (first two interrupts are bad)),以及将默认时间片更改为1毫秒(有关示例/说明,请参阅Why are .NET timers limited to 15 ms resolution?)。
在任何情况下,如果要安排其他更高优先级的线程并且您的所有工作都将丢失,您应该知道您的代码可能会丢失其时间片。
注意:您显然应该考虑更合理的数据结构是否更合适(即堆或优先级队列可能更适合查找下一个项目)。
答案 1 :(得分:1)
正如您所发现的,在CPU上“等待”的最准确方法是轮询RTC。然而,这是计算密集型的。如果你需要在时间上达到时钟精度,那么别无他法。
然而,在您的原始帖子中,您说时间大约为15毫秒。
在我家的3.3GHz四核i5上,15ms x 3.3GHz = 50万个时钟周期(如果计算所有内核,则为2亿)。
那是永恒的。
松弛的睡眠时间很可能超出您的目的。
坦率地说,如果你需要Hard RT,那么在Windows内核上的.net GC上运行的.net VM上的C#是错误的选择。