任务间通信

FreeRTOS队列

[另请参阅阻止多个RTOS对象 ]

队列是任务间通信的主要形式。它们可以用来在任务之间以及中断和任务之间发送消息。在大多数情况下,它们被用作线程安全FIFO(先入先出)缓冲区,新数据被发送到队列的后面,尽管数据也可以发送到前端。


写入和读取队列。在这个例子中,队列被创建为保存5个项目,并且队列永远不会变满。


用户模型:最大简单性,最大灵活性。

FreeRTOS队列使用模型设法将简单性和灵活性结合在一起 - 通常是互斥的属性。消息通过复制发送到队列中,这意味着数据(可以是指向较大缓冲区的指针)本身被复制到队列中,而不是始终仅存储对数据的引用的队列。这是最好的方法,因为:
  • 已经包含在C变量(整数,小结构等)中的小消息可以直接发送到队列中。不需要为消息分配缓冲区,然后将该变量复制到分配的缓冲区中。同样,消息可以从队列直接读入C变量。

    此外,以这种方式发送到队列允许发送任务立即覆盖发送到队列的变量或缓冲区,即使发送的消息仍在队列中。因为变量中包含的数据被复制到队列中,变量本身可供重用。发送消息的任务和接收消息的任务不需要同意哪个任务拥有消息,并且不再需要哪个任务负责释放消息。

  • 使用通过副本传递数据的队列不会阻止队列被用于通过引用传递数据。当消息的大小达到了将整个消息复制到字节的队列字节是不切实际的地步时,定义队列来保存指针,而只是将指向消息的指针复制到队列中。这正是FreeRTOS + UDP 实现如何 通过FreeRTOS IP堆栈周围的大型网络缓冲区。

  • 内核负责分配用作队列存储区域的内存。

  • 变量大小的消息可以通过定义队列来发送,以保存包含指向排队消息的成员的结构和保存排队消息大小的另一成员。

  • 单个队列可用于接收不同的消息类型和来自多个位置的消息,方法是定义队列以保存具有保存消息类型成员的结构,另一个成员保存消息数据(或指向消息数据)。数据如何解释取决于消息类型。这正是管理FreeRTOS + UDP IP堆栈的任务 能够如何使用单个队列接收ARP定时器事件通知,从以太网硬件接收的数据包,从应用程序接收的数据包,网络中断事件等。

  • 该实现自然适合在内存保护环境中使用。限于受保护内存区域的任务可以将数据传递给限制于不同受保护内存区域的任务,因为通过调用队列发送函数来调用RTOS将提高微控制器特权级别。队列存储区只能由RTOS访问(具有完全权限)。

  • 提供一个独立的API用于中断内部。将从RTOS任务中使用的API与从中断服务例程中使用的API分开,意味着RTOS API函数的实现不会承担每次执行时检查其调用上下文的开销。使用单独的中断API也意味着,在大多数情况下,创建RTOS感知中断服务程序对于终端用户来说比对比替代RTOS产品更简单。

  • 无论如何,API更简单。

FreeRTOS的教程书 提供队列的更多信息,二进制信号量,互斥,计数信号量和递归信号量,在一组随附示例项目的简单工作的例子沿。


阻塞队列

队列API函数允许指定块时间。

当任务尝试从空队列中读取时,任务将被置于阻塞状态(因此它不会消耗任何CPU时间并可以运行其他任务),直到数据在队列中可用或者阻塞时间到期。

当任务尝试写入完整队列时,任务将进入阻塞状态(因此它不消耗任何CPU时间并可以运行其他任务),直到队列中的任何空间变为可用或阻塞时间结束。

如果同一队列中有多个任务块,则具有最高优先级的任务将成为首先解除阻塞的任务。

请参阅用户文档队列管理部分以获取与队列相关的API函数列表。搜索FreeRTOS / Demo / Common / Minimal目录中的文件将显示其使用情况的多个示例。

请注意,中断不得使用不以“FromISR”结尾的API函数。

FreeRTOS二进制信号量

二进制信号用于互斥和同步目的。

二进制信号量和互斥量非常相似,但有一些细微差别:互斥量包括优先级继承机制,二进制信号量不包含。这使得二进制信号量成为实现同步(任务之间或任务与中断之间)的更好选择,并且互斥实现简单互斥的更好选择。描述的互斥体是如何被用作一个互斥机制的二进制信号也同样成立。本小节将只描述使用二进制信号进行同步。

信号量API函数允许指定块时间。阻塞时间指示当信号量不可立即可用时,任务在尝试“采取”信号量时应进入阻塞状态的最大“节拍数”。如果多个任务在同一个信号量上阻塞,那么具有最高优先级的任务将在下一次信号量变为可用时解除阻塞。

将二进制信号量想象成只能容纳一个项目的队列。队列因此只能是空的或全部的(因此是二进制的)。使用队列的任务和中断不关心队列是什么 - 他们只想知道队列是空的还是满的。这种机制可以被利用来将任务与中断同步(例如)。

考虑使用任务来为外设提供服务的情况。轮询外设会浪费CPU资源,并阻止执行其他任务。因此,最好是任务大部分时间都处于阻塞状态(允许其他任务执行),并且只有在实际有事情需要时才执行。这是通过在尝试“取”信号量时使用任务Block来使用二进制信号量来实现的。然后为外设写一个中断程序,当外设需要维修时,该程序只是“给”信号量。该任务总是'取得'信号量(从队列中读取以使队列为空),但从不'给出'它。中断总是'给''信号量(写入队列使其满),但从不接受它。xSemaphoreGiveFromISR()文档页面应该使这个更清晰。另请参阅RTOS任务通知,在某些情况下可用作更快,更轻的二进制信号量替代品。

可以使用任务优先级确保外围设备及时获得服务 - 有效地生成“延迟中断”方案。(注意FreeRTOS也有一个内置的延迟中断机制)。另一种方法是使用队列来代替信号量。完成此操作后,中断例程可以捕获与外设事件关联的数据,并将其发送到队列中以发送给任务。当数据在队列中可用时,该任务将取消阻塞,从队列中检索数据,然后执行所需的任何数据处理。第二种方案允许中断尽可能短,所有的后处理都在一个任务中进行。

请参阅用户文档Semaphores / Mutexes部分以获取信号量相关的API函数列表。搜索FreeRTOS / Demo / Common / Minimal目录中的文件将显示其使用情况的多个示例。请注意,中断不得使用不以“FromISR”结尾的API函数。


使用信号量将任务与中断同步。只有中断'给''信号量,而任务只'取'信号量。

FreeRTOS计数信号量

正如二进制信号量可以被认为是长度为1的队列一样,计数信号量可以被认为是长度大于1的队列。同样,信号量的用户对存储在队列中的数据不感兴趣 - 只是队列是否为空。

计数信号量通常用于两件事情:

  1. 计数事件。

在这种使用场景中,事件处理程序会在每次发生事件(增加信号量计数值)时一个信号量,并且每次处理事件(递减信号量计数值)时,处理程序任务都会采取一个信号量。因此,计数值是发生的事件数量与已处理的数量之间的差值。在这种情况下,当信号量被创建时,计数值最好为零。

  1. 资源管理。

在这种使用情况下,计数值表示可用资源的数量。要获得对资源的控制,任务必须首先获得一个信号 - 递减信号计数值。当计数值达到零时,没有空闲资源。当一个任务完成资源处理时,它会返回信号量 - 递增信号计数值。在这种情况下,希望计数值等于创建信号量时的最大计数值。

 

FreeRTOS互斥体

互斥体是包含优先级继承机制的二进制信号量。二进制信号量是实现同步的更好选择(在任务之间或任务与中断之间),互斥锁是实现简单互斥(因此'MUT''排除')的更好选择。

当互斥使用时,互斥就像用来守护资源的令牌。当任务希望访问资源时,它必须首先获取('')令牌。当资源完成后,它必须该令牌 - 允许其他任务有机会访问相同的资源。

互斥量使用相同的信号量访问API函数,因此也允许指定块时间。阻止时间表示当互斥体不是立即可用时,如果尝试互斥体,任务应进入阻塞状态的最大节拍数。与二进制信号量不同 - 互斥量使用优先级继承。这意味着如果一个高优先级的任务在尝试获取当前由较低优先级任务持有的互斥体(令牌)时阻塞,则持有该令牌的任务的优先级暂时升高到阻塞任务的优先级。该机制旨在确保优先级较高的任务在尽可能短的时间内处于阻塞状态,从而尽量减少已发生的优先级反转

优先级继承不能治愈优先级倒置!它在某些情况下将其影响降至最低。硬实时应用程序的设计应该优先反转不首先发生。

不应该从中断中使用互斥锁,因为:

  • 它们包含一个优先级继承机制,只有当互斥量是从任务给出并从中取出时才有意义。
  • 中断不能阻止等待由互斥锁保护的资源变为可用。


使用互斥锁来保护对共享资源的访问。

FreeRTOS递归互斥

一个递归使用的互斥锁可以被所有者重复使用。在所有者为每个成功的xSemaphoreTakeRecursive()请求调用xSemaphoreGiveRecursive()之前,互斥锁不会再次可用。例如,如果某个任务成功'取得'相同的互斥锁5次,则该互斥锁将不可用于任何其他任务,直到它还将该互斥锁'给出'5次。

这种类型的信号量使用优先级继承机制,因此一旦信号量不再需要,信号量的任务必须总是'''信号量。

中断服务程序中不能使用互斥锁类型信号量。

不应该从中断中使用互斥锁,因为:

  • 它们包含一个优先级继承机制,只有当互斥量是从任务给出并从中取出时才有意义。
  • 中断不能阻止等待由互斥锁保护的资源变为可用。

 



 




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值