队列又称消息队列,是一种常用于任务间通信的数据结构, 队列可以在任务与任务间、中断和任务间传递信息,实现了任务接收来自其他任务或中断的不固定长度的消息,任务能够从队列里面读取消息,当队列中的消息是空时,读取消息的任务将被阻塞,用户还可以指定阻塞的任务时间 xTicksToWait,在这段时间中,如果队列为空,该任务将保持阻塞状态以等待队列数据有效。 当队列中有新消息时, 被阻塞的任务会被唤醒并处理新消息;当等待的时间超过了指定的阻塞时间,即使队列中尚无有效数据,任务也会自动从阻塞态转为就绪态。 消息队列是一种异步的通信方式。
通过消息队列服务,任务或中断服务例程可以将一条或多条消息放入消息队列中。同样,一个或多个任务可以从消息队列中获得消息。当有多个消息发送到消息队列时,通常是将先进入消息队列的消息先传给任务,也就是说,任务先得到的是最先进入消息队列的消息,即先进先出原则(FIFO),但是也支持后进先出原则(LIFO) 。
FreeRTOS 中使用队列数据结构实现任务异步通信工作,具有如下特性:
- 消息支持先进先出方式排队,支持异步读写工作方式。
- 读写队列均支持超时机制。
- 消息支持后进先出方式排队, 往队首发送消息(LIFO) 。
- 可以允许不同长度(不超过队列节点最大值)的任意类型消息。
- 一个任务能够从任意一个消息队列接收和发送消息。
- 多个任务能够从同一个消息队列接收和发送消息。
- 当队列使用结束后,可以通过删除队列函数进行删除
任务或者中断服务程序都可以给消息队列发送消息, 当发送消息时, 如果队列未满或者允许覆盖入队, FreeRTOS 会将消息拷贝到消息队列队尾,否则,会根据用户指定的阻塞超时时间进行阻塞,在这段时间中,如果队列一直不允许入队,该任务将保持阻塞状态以等待队列允许入队。当其它任务从其等待的队列中读取入了数据(队列未满),该任务将自动由阻塞态转移为就绪态。当等待的时间超过了指定的阻塞时间,即使队列中还不允许入队,任务也会自动从阻塞态转移为就绪态,此时发送消息的任务或者中断程序会收到一个错误码 errQUEUE_FULL。
发送紧急消息的过程与发送消息几乎一样,唯一的不同是,当发送紧急消息时, 发送的位置是消息队列队头而非队尾,这样,接收者就能够优先接收到紧急消息,从而及时进行消息处理。
当某个任务试图读一个队列时,其可以指定一个阻塞超时时间。在这段时间中,如果队列为空,该任务将保持阻塞状态以等待队列数据有效。当其它任务或中断服务程序往其等待的队列中写入了数据,该任务将自动由阻塞态转移为就绪态。当等待的时间超过了指定的阻塞时间,即使队列中尚无有效数据,任务也会自动从阻塞态转移为就绪态。
当消息队列不再被使用时,应该删除它以释放系统资源,一旦操作完成,消息队列将被永久性的删除。
消息队列的运作过程具体见图

因为 FreeRTOS 已经为我们做好了,我们直接使用就好了,每个对消息队列读写的函数,都有这种机制,我称之为阻塞机制。假设有一个任务 A 对某个队列进行读操作的时候(也就是我们所说的出队),发现它没有消息,那么此时任务 A 有 3 个选择:第一个选择,任务 A 扭头就走,既然队列没有消息,那我也不等了,干其它事情去,这样子任务 A 不会进入阻塞态;第二个选择,任务 A 还是在这里等等吧,可能过一会队列就有消息,此时任务 A 会进入阻塞状态,在等待着消息的道来,而任务 A 的等待时间就由我们自己定义,比如设置 1000 个系统时钟节拍 tick 的等待,在这 1000 个 tick 到来之前任务 A 都是处于阻塞态,当阻塞的这段时间任务 A 等到了队列的消息,那么任务 A 就会从阻塞态变 成就绪态,如果此时任务 A 比当前运行的任务优先级还高,那么,任务 A 就会得到消息并且运行;假如 1000 个 tick 都过去了,队列还没消息,那任务 A 就不等了,从阻塞态中唤醒,返回一个没等到消息的错误代码,然后继续执行任务 A 的其他代码;第三个选择,任务 A 死等,不等到消息就不走了,这样子任务 A 就会进入阻塞态,直到完成读取队列的消息。
而在发送消息操作的时候,为了保护数据,当且仅当队列允许入队的时候,发送者才能成功发送消息;队列中无可用消息空间时,说明消息队列已满,此时,系统会根据用户指定的阻塞超时时间将任务阻塞,在指定的超时时间内如果还不能完成入队操作,发送消息的任务或者中断服务程序会收到一个错误码 errQUEUE_FULL,然后解除阻塞状态;当然, 只有在任务中发送消息才允许进行阻塞状态,而在中断中发送消息不允许带有阻塞机制的,需要调用在中断中发送消息的 API 函数接口,因为发送消息的上下文环境是在中断中,不允许有阻塞的情况。
假如有多个任务阻塞在一个消息队列中,那么这些阻塞的任务将按照任务优先级进行排序,优先级高的任务将优先获得队列的访问权。
消息队列可以应用于发送不定长消息的场合,包括任务与任务间的消息交换,队列是FreeRTOS 主要的任务间通讯方式,可以在任务与任务间、中断和任务间传送信息,发送到队列的消息是通过拷贝方式实现的, 这意味着队列存储的数据是原数据,而不是原数据的引用。

创建了一个用于任务 A 与任务 B 之间“沟通交流”的队列,这个队列最大可容纳 5 个队列项目,即队列的长度为 5。刚创建的队列是不包含内容的,因此这个队列为空。

任务 A 将一个私有变量写入队列的尾部。由于在写入队列之前,队列是空的,因此新写入的消息,既是是队列的头部,也是队列的尾部。


任务 B 从队列中读取消息,任务 B 读取的消息是处于队列头部的消息,这是任务 A 第一次往队列中写入的消息。在任务 B 从队列中读取消息后,队列中任务 A 第二次写入的消息,变成了队列的头部,因此下次任务 B 再次读取消息时,将读取到这个消息。此时队列中剩余 4 个空闲的位置
到此这篇阻塞队列和普通队列(阻塞队列和就绪队列)的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权、违法违规、事实不符,请将相关资料发送至xkadmin@xkablog.com进行投诉反馈,一经查实,立即处理!
转载请注明出处,原文链接:https://www.xkablog.com/bcyy/20840.html