为了进行任务间通信或在RTOS的两个任务之间共享数据,我们使用队列。但是队列的问题是它们的速度很慢。...他们先将数据复制到Buffer中,然后再进行Mutex处理,然后再进行数据传输。如果必须传输大数据,这会很烦人。另一个问题是,如果多个任务访问同一队列。然后图片变成这样:-首先等待访问Queue,然后对内部Mutex处理队列,然后进行数据传输。
这增加了系统的开销。什么是队列的有效替代品?
(我想这个问题是我们使用的RTOS的独立性。大多数RTOS仅以这种方式处理队列)
为了进行任务间通信或在RTOS的两个任务之间共享数据,我们使用队列。但是队列的问题是它们的速度很慢。...他们先将数据复制到Buffer中,然后再进行Mutex处理,然后再进行数据传输。如果必须传输大数据,这会很烦人。另一个问题是,如果多个任务访问同一队列。然后图片变成这样:-首先等待访问Queue,然后对内部Mutex处理队列,然后进行数据传输。
这增加了系统的开销。什么是队列的有效替代品?
(我想这个问题是我们使用的RTOS的独立性。大多数RTOS仅以这种方式处理队列)
Answers:
队列以这种方式运行,因为这是用于任务间通信的线程安全事务模型。在任何不那么严格的方案中,您都有数据损坏和/或所有权问题的风险。
您是将数据复制到内存中的缓冲区中,然后将指针与队列元素一起传递,还是试图将队列元素本身中的所有数据传递?如果您不传递指针,那么这样做将提高性能,而不是一次通过队列元素传递一个字节。
可以针对单个生产者/单个消费者的情况实现无锁队列,并且通常您可以设计软件以最小化多个生产者或多个消费者队列的数量。
可以这样构造无锁队列:分配要通信的元素的数组,还有两个整数,分别称为Head和Tail。Head是数组的索引,将在其中添加下一项。尾巴是数组的索引,可以删除下一项。生产者任务读取H和T来确定是否有添加项目的空间。将项目写入H索引,然后更新H。使用者任务读取H和T,以确定是否有可用数据,从索引T读取数据,然后更新T。基本上,这是两个任务访问的环形缓冲区,并且操作顺序(插入,然后更新H;删除,然后更新T)可确保不会发生数据损坏。
如果您有多个生产者和一个消费者,或者一个生产者和多个消费者的情况,那么您实际上会有某种资源限制,除了使用同步之外,别无其他,因为性能限制器更有可能比起带有锁定机制的OS开销,它是唯一的生产者/消费者。
但是,如果您有多个生产者和消费者,则值得花时间(在设计空间中)看看您是否无法获得更协调的沟通机制。在这种情况下,通过单个队列序列化所有内容肯定会使队列的效率成为性能的中心决定因素。
如果队列本身保存的项目足够小,可以与不包含负载存储,比较交换或类似原语的项目一起使用,则可以在无锁的多生产者单消费者队列中获得有效的操作,并且可以使用一个空队列插槽的保留值或保留值。当写入队列时,写入器进行一个比较交换,以尝试将其数据存储到下一个空插槽中。如果失败,则编写器尝试以下插槽。尽管队列维护着指向下一个空插槽的指针,但指针值为“ advisory”。请注意,如果系统使用比较交换而不是专用于负载存储,则可能需要具有不同“空插槽”值的“系列”。否则,如果在编写者发现空队列插槽并尝试对其进行写入的时间之间,另一位作者写入该插槽,而读者读取该插槽,则第一位作者在不知不觉中将其数据放置在读者看不到的位置。在使用独占负载存储的系统中不会发生此问题,因为独占存储将检测到即使已将数据写回到旧值也已写入的数据。
队列并不是天生就慢。它们的实现可能是。
如果您盲目地复制数据并使用同步队列,则会发现性能下降。
正如其他海报所指出的,有无锁替代品。单生产者/单消费者的情况很简单。对于多个生产者和消费者,Michael和Scott的无锁队列算法(它们是他们的姓氏)是标准,并且用作Java的ConcurrentLinkedQueue的基础。
在某些情况下可以优化对队列的需求,但是它们提供了并发保证,通过允许您解耦任务,通常可以为系统带来巨大的简化收益。