替换 RTOS 中的队列

电器工程 rtos
2022-01-19 10:13:10

对于任务间通信或在 RTOS 的两个任务之间共享数据,我们使用队列。但是队列的问题是它们很慢......它们在缓冲区中复制数据,然后是互斥体处理,然后是数据传输。如果您必须传输大数据,速度会非常慢。另一个问题是多个任务是否访问同一个队列。然后图片变成这样:-首先等待访问队列然后队列内部互斥处理然后数据传输。

这增加了系统的开销。队列的有效替代品可能是什么?

(我猜这个问题与我们使用的 RTOS 无关。大多数 RTOS 仅以这种方式处理队列)

4个回答

队列以这种方式运行,因为这是用于任务间通信的线程安全事务模型。在任何不太严格的方案中,您都面临着数据损坏和/或所有权问题的风险。

您是将数据复制到内存中的缓冲区中,然后将指针与队列元素一起传递,还是尝试将队列元素中的所有数据本身传递?如果您不传递指针,那么这样做会提高性能,而不是一次通过队列元素传递一个字节。

一种简单的方法是在队列中放置一个指向数据的指针并使用该指针使用数据。

请注意,您以这种方式以安全换取性能,因为您必须确保:

  1. 缓冲区保持有效,直到消费者消费完数据
  2. 有人释放缓冲区

如果您不使用动态分配的内存,则不必释放它,但您仍然必须确保在使用数据之前未重用内存区域。

可以为单生产者/单消费者情况实现无锁队列,并且通常您可以构建您的软件以最小化多生产者或多消费者队列的数量。

无锁队列可以这样构造:分配要通信的元素的数组,以及两个整数,分别称为 Head 和 Tail。Head 是数组的索引,将在其中添加下一项。Tail 是数组的索引,可以删除下一项。生产者任务读取 H 和 T 以确定是否有空间添加项目;将项目写入 H 索引处,然后更新 H。消费者任务读取 H 和 T 以确定是否有可用数据,从索引 T 读取数据,然后更新 T。基本上它是由两个任务访问的环形缓冲区,并且操作顺序(插入,然后更新 H;删除,然后更新 T)确保不会发生数据损坏。

如果你有多个生产者和一个消费者,或者一个生产者和多个消费者的情况,你实际上有某种资源限制,除了使用同步之外别无他法,因为性能限制器更有可能成为唯一的生产者/消费者,而不是具有锁定机制的操作系统开销。

但是,如果您有多个生产者和消费者,那么值得花时间(在设计空间中)看看您是否无法获得更协调的通信机制;在这种情况下,通过单个队列将所有内容序列化肯定会使队列的效率成为性能的核心决定因素。

如果队列本身包含的项目足够小,可以与 load-store-exclusive、compare-exchange 或类似原语一起使用,则可以在无锁多生产者单消费者队列中获得高效操作,并且可以使用保留值或空队列槽的保留值。当写入队列时,写入者进行比较交换以尝试将他的数据存储到下一个空槽中;如果失败,作者会尝试下一个插槽。虽然队列维护了一个指向下一个空槽的指针,但指针值是“advisory”。请注意,如果系统使用 compare-exchange 而不是 load-store-exclusive,则可能需要具有不同“empty slot”值的“family”。否则,如果在作者发现一个空队列槽并尝试写入它的时间之间,另一个写入者写入插槽并且读者读取它,第一个写入者会在不知不觉中将他的数据放在读者看不到的地方。在使用 load-store-exclusive 的系统中不会出现此问题,因为 store-exclusive 会检测到数据已被写入,即使它已被写回旧值。