FreeRTOS---------任务通知

FreeRTOS 从 V8.2.0版本开始提供任务通知这个功能,每个任务都有一个32位的通知 值,在大多数情况下,任务通知可以替代二值信号量、计数信号量、事件组,也可以替代 长度为1的队列(可以保存一个32位整数或指针值)。

相对于以前使用 FreeRTOS 内核通信的资源,必须创建队列、二进制信号量、计数信 号量或事件组的情况,使用任务通知显然更灵活。按照 FreeRTOS 官方的说法,使用任务 通知比通过信号量等 ICP 通信方式解除阻塞的任务要快 45%,并且更加省 RAM内存空间


FreeRTOS 提供以下几种方式发送通知给任务 :

  •  发送通知给任务, 如果有通知未读,不覆盖通知值。
  •  发送通知给任务,直接覆盖通知值。
  •  发送通知给任务,设置通知值的一个或者多个位 ,可以当做事件组来使用。
  •  发送通知给任务,递增通知值,可以当做计数信号量使用。

通过对以上任务通知方式的合理使用,可以在一定场合下替代 FreeRTOS的信号量, 队列、事件组等。


当然,凡事都有利弊,不然的话 FreeRTOS 还要内核的 IPC通信机制干嘛,消息通知虽然处理更快,RAM开销更小,但也有以下限制

  •  只能有一个任务接收通知消息,因为必须指定接收通知的任务。
  •  只有等待通知的任务可以被阻塞,发送通知的任务,在任何情况下都不会因为发 送失败而进入阻塞态。

任务通知可以在任务中向指定任务发送通知,也可以在中断中向指定任务发送通知, FreeRTOS 的每个任务都有一个 32 位的通知值,任务控制块中的成员变量 ulNotifiedValue 就是这个通知值。只有在任务中可以等待通知,而不允许在中断中等待通知。

如果任务在等待的通知暂时无效,任务会根据用户指定的阻塞超时时间进入阻塞状态,我们可以将等 待通知的任务看作是消费者;其它任务和中断可以向等待通知的任务发送通知,发送通知 的任务和中断服务函数可以看作是生产者,当其他任务或者中断向这个任务发送任务通知, 任务获得通知以后,该任务就会从阻塞态中解除,这与FreeRTOS中内核的其他通信机制 一致。

任务通知的函数接口讲解

发送任务通知函数

xTaskGenericNotify()

这里的任务通知发送函数也是利用宏定义来进行扩展的,所有的函数都是一个宏定义,在 任务中发送任务通知的函数均是调用 xTaskGenericNotify()函数进行发送通知。

xTaskGenericNotify()函数是一个通用的任务通知发送函数,在任务中发送通知的API 函数,如xTaskNotifyGive()、xTaskNotify()、xTaskNotifyAndQuery(),都是以 xTaskGenericNotify()为原型的,只不过指定的发送方式不同而已。


xTaskNotifyGive()

xTaskNotifyGive()是一个宏,宏展开是调用函数xTaskNotify( ( xTaskToNotify ), ( 0 ), eIncrement ),即向一个任务发送通知,并将对方的任务通知值加1。该函数可以作为二值 信号量和计数信号量的一种轻量型的实现,速度更快,在这种情况下对象任务在等待任务 通知的时候应该是使用函数 ulTaskNotifyTake() 而不是xTaskNotifyWait() 。xTaskNotifyGive()不能在中断里面使用,而是使用具有中断保护功能的 vTaskNotifyGiveFromISR()来代替。


vTaskNotifyGiveFromISR()

vTaskNotifyGiveFromISR()是vTaskNotifyGive()的中断保护版本。

用于在中断中向指定 任务发送任务通知,并更新对方的任务通知值(加1操作),在某些场景中可以替代信号 量操作,因为这两个通知都是不带有通知值的。


xTaskNotify()

FreeRTOS 每个任务都有一个 32 位的变量用于实现任务通知,在任务创建的时候初始 化为 0。这个 32 位的通知值在任务控制块 TCB 里面定义,具体见代码清单 22-6。 xTaskNotify()用于在任务中直接向另外一个任务发送一个事件,接收到该任务通知的任务 有可能解锁。如果你想使用任务通知来实现二值信号量和计数信号量,那么应该使用更加 简单的函数 xTaskNotifyGive() ,而不是使用 xTaskNotify(),xTaskNotify()函数在发送任务 通知的时候会指定一个通知值,并且用户可以指定通知值发送的方式。 注意:该函数不能在中断里面使用,而是使用具体中断保护功能的版本函数 xTaskNotifyFromISR()。xTaskNotify()函数的具体说明见表格

xTaskNotifyFromISR()

xTaskNotifyFromISR()是 xTaskNotify()的中断保护版本,真正起作用的函数是中断发送 任务通知通用函数xTaskGenericNotifyFromISR(),而xTaskNotifyFromISR()是一个宏定义。


中断中发送任务通知通用函数

xTaskGenericNotifyFromISR()

xTaskGenericNotifyFromISR()是一个在中断中发送任务通知的通用函数, xTaskNotifyFromISR()、xTaskNotifyAndQueryFromISR()等函数都是以其为基础。


xTaskNotifyAndQuery()

xTaskNotifyAndQuery()与xTaskNotify()很像,都是调用通用的任务通知发送函数 xTaskGenericNotify()来实现通知的发送,不同的是多了一个附加的参数 pulPreviousNotifyValue用于回传接收任务的上一个通知值。

xTaskNotifyAndQuery()函数不能用在中断中,而是必须使用带中断保护功能的 xTaskNotifyAndQuery()FromISR来代替。


xTaskNotifyAndQueryFromISR()

xTaskNotifyAndQueryFromISR()是xTaskNotifyAndQuery ()的中断版本,用于向指定的 任务发送一个任务通知,并返回对象任务的上一个通知值,该函数也是一个宏定义,真正 实现发送通知的是xTaskGenericNotifyFromISR()。

获取任务通知函数

既然FreeRTOS中发送任务的函数有那么多个,那么任务怎么获取到通知呢?我们说 了,任务通知在某些场景可以替代信号量、消息队列、事件等。获取任务通知函数只能用 在任务中,没有带中断保护版本,因此只有两个API函数:ulTaskNotifyTake()和 xTaskNotifyWait ()。前者是为代替二值信号量和计数信号量而专门设计的,它和发送通知 API函数xTaskNotifyGive()、vTaskNotifyGiveFromISR()配合使用;后者是全功能版的等待 通知,可以根据不同的参数实现轻量级二值信号量、计数信号量、事件组和长度为1的队 列。

所有的获取任务通知API函数都带有指定阻塞超时时间参数,当任务因为等待通知而 进入阻塞时,用来指定任务的阻塞时间,这些超时机制与FreeRTOS的消息队列、信号量、 事件等的超时机制一致。


ulTaskNotifyTake()

ulTaskNotifyTake()作为二值信号量和计数信号量的一种轻量级实现,速度更快。如果 FreeRTOS中使用函数xSemaphoreTake() 来获取信号量,这个时候则可以试试使用函数 ulTaskNotifyTake()来代替。 对于这个函数,任务通知值为0,对应信号量无效,如果任务设置了阻塞等待,任务 被阻塞挂起。当其他任务或中断发送了通知值使其不为0后,通知变为有效,等待通知的 任务将获取到通知,并且在退出时候根据用户传递的第一个参数xClearCountOnExit选择清 零通知值或者执行减一操作。

xTaskNotifyTake()在退出的时候处理任务的通知值的时候有两种方法,一种是在函数 退出时将通知值清零,这种方法适用于实现二值信号量;另外一种是在函数退出时将通知 值减1,这种方法适用于实现计数信号量。

当一个任务使用其自身的任务通知值作为二值信号量或者计数信号量时,其他任务应 该使用函数xTaskNotifyGive()或者xTaskNotify( ( xTaskToNotify ), ( 0 ), eIncrement )来向其 发送信号量。如果是在中断中,则应该使用他们的中断版本函数。


xTaskNotifyWait()

xTaskNotifyWait()函数用于实现全功能版的等待任务通知,根据用户指定的参数的不 同,可以灵活的用于实现轻量级的消息队列队列、二值信号量、计数信号量和事件组功能, 并带有超时等待。

任务通知在一定程度上可以代替信号量队列和事件组,但是在减小内存开销和响应速度的同时对使用方法上也同样会有一定限制,视情况而定。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值