几年前我也遇到过同样的问题(如果我理解正确的话),我有一个解决方案。一篇包含算法的期刊论文已被接受,我会在它发表时在此处提供参考,但现在,我可以将您引导至代码。
然而,首先,这是在 C 中实时完成的,并且(当前)可能使用 POSIX 后端(在用户空间中)或 RTAI 后端(在用户空间或内核空间中)。
其次,我的一个要求是作者永远不会因为用户而被阻止。也就是说,如果写入器找不到空闲缓冲区,它会覆盖当前数据帧。我也解决了这个问题,我的测试表明,只要在读者方面进行少量协作,就可以完全避免这种情况。
还要注意,这个想法类似于“周期性数据缓冲区”1 和“循环异步缓冲区”2,尽管我是自己提出的。他们使用原子操作,而我使用读写锁。此外,它们没有提供我上面提到的“交换跳过”的解决方案。
最后,作者和读者不仅仅是周期性的。编写者可以是定期的或零星的(根据请求运行),而读者可以是定期的、零星的或尽力而为。
您可以找到编写器实现here 和读取器实现here。
为了完整起见,我将使用多缓冲区模式下周期性写入器和读取器的基本算法粘贴注释:
Writer:
write_lock(cur)
loop {
if last period no swap
try swap again
write
try while period left
write_lock(next)
write_unlock(cur)
cur = next
wait period
}
unlock(cur)
Reader:
loop {
if last is new
b = last
else
b = cur
read_lock(b)
read
read_unlock(b)
wait period
}
在write 上,写入器还会为缓冲区中的数据加上时间戳。这有助于读者了解数据是新的还是旧的。
关于 writer 中的缓冲区交换的要点是,它会尝试,直到成功或接近其交换缓冲区的周期结束。这是通过try_locking 所有其他缓冲区来完成的,以查看哪些可用(在第一次成功/期末停止)(当然没有忙循环)。完成此操作后,它还会告知(通过共享内存,可能与包含数据缓冲区的内存相同)何时希望再次交换缓冲区,以及哪个缓冲区包含最新数据(last),以及写入者当前控制哪个缓冲区 (cur)。
然后读者可以选择。如果last 包含新数据,read_lock 它并继续读取。如果不是,或者如果阅读器可以估计它无法及时执行下一次缓冲区交换的读取,它会等待cur 解锁。一旦写入器解锁,实时调度器就会尽快唤醒读取器。如果系统负载不重,这意味着几乎是瞬间的。
为了让读者知道它是否可以及时执行读取,它会跟踪它在周期中的平均执行时间,并使用它来检查是否current_time + my_execution_time > next_expected_swap。在这种情况下,它无法及时执行读取,因此它将改为等待即将解锁的cur。
1 “HIC:一种用于伺服回路层次结构的操作系统”,Clark, D.,机器人与自动化,1989 年。Proceedings.,1989 年 IEEE 国际会议
2“HARTIK:机器人应用程序的实时内核”,Buttazzo, G.C.,实时系统研讨会,1993 年,论文集。
注意:虽然这个库主要是为机器人皮肤数据处理而设计的,但您基本上可以将它用于具有上述属性的任何一般的读写器通信。此外,请注意我指向的存储库的主分支包含旧版本。我指向的分支skinware-2 有一个更好且功能更丰富的实现。