9.1本章介绍与范围
已经看到,使用FreeRTOS的应用程序被构造为一组独立的任务,并且这些任务很可能必须彼此通信,以便它们可以共同提供有用的系统功能。
通过中介对象进行通信
本书已经描述了任务之间可以相互通信的各种方式。 到目前为止描述的方法需要创建通信对象。 通信对象的示例包括队列,事件组和各种不同类型的信号量。
使用通信对象时,事件和数据不会直接发送到接收任务或接收ISR,而是会发送到通信对象。 同样,任务和ISR从通信对象接收事件和数据,而不是直接从发送事件或数据的任务或ISR接收事件和数据。 这在图76中进行了描述。
任务通知-直接进行任务通信
“任务通知”允许任务与其他任务进行交互,并与ISR同步,而无需单独的通信对象。 通过使用任务通知,任务或ISR可以将事件直接发送到接收任务。 这在图77中进行了描述。
任务通知功能是可选的。 要包括任务通知功能,请在FreeRTOSConfig.h中将configUSE_TASK_NOTIFICATIONS设置为1。
当configUSE_TASK_NOTIFICATIONS设置为1时,每个任务都有一个“通知状态”(可以是“挂起”或“未挂起”)和一个“通知值”(一个32位无符号整数)。 当一个任务收到通知,其通知状态设置为挂起。 当任务读取其通知值时,其通知状态将设置为“未挂起”。
任务可以在“阻止”状态下等待,并具有可选的超时时间,以使其通知状态变为挂起状态。
范围
本章旨在使读者更好地理解:
- 任务的通知状态和通知值。
- 如何以及何时可以使用任务通知代替通信对象(例如信号量)。
- 使用任务通知代替通信对象的优点。
9.2任务通知; 好处和局限性
任务通知的性能优势
使用任务通知将事件或数据发送到任务比使用队列,信号量或事件组执行等效操作要快得多。
任务通知的RAM足迹优势
同样,与使用队列,信号量或事件组执行等效操作相比,使用任务通知将事件或数据发送到任务所需的RAM要少得多。 这是因为必须先创建每个通信对象(队列,信号量或事件组),然后才能使用它,而启用任务通知功能具有固定的开销,即每个任务只有8个字节的RAM。
任务通知的局限性
与通信对象相比,任务通知速度更快并且使用的RAM更少,但是任务通知不能在所有情况下都使用。 本节介绍了无法使用任务通知的方案:
-
将事件或数据发送到ISR
通信对象可用于从ISR向任务以及从任务向ISR发送事件和数据。
任务通知可用于将事件和数据从ISR发送到任务,但不能用于将事件或数据从任务发送到ISR。 -
启用多个接收任务
任何知道其句柄(可能是队列句柄,信号量句柄或事件组句柄)的任务或ISR都可以访问该通信对象。 任何数量的任务和ISR都可以处理发送到任何给定通信对象的事件或数据。
任务通知直接发送到接收任务,因此只能由发送通知的任务处理。 但是,这在实际情况中很少受到限制,因为尽管有多个任务和ISR发送到相同的通信对象是很常见的,但很少有多个任务和ISR从同一个通信对象接收到。 -
缓冲多个数据项
队列是一次可以容纳多个数据项的通信对象。 已发送到队列但尚未从队列接收的数据被缓冲在队列对象中。
任务通知通过更新接收任务的通知值将数据发送到任务。 任务的通知值一次只能保存一个值。 -
广播多个任务
事件组是一个通信对象,可用于一次将事件发送到多个任务。
任务通知直接发送到接收任务,因此只能由接收任务处理。 -
在阻止状态下等待发送完成
如果通信对象暂时处于无法再写入任何数据或事件的状态(例如,当队列已满时,无法再向该队列发送任何数据),则尝试写入该对象的任务可以 (可选)进入“阻止”状态,以等待其写入操作完成。
如果任务试图将任务通知发送到已经有待处理的通知的任务,则发送任务不可能在“阻止”状态下等待接收任务重置其通知状态。 可以看出,在使用任务通知的实际情况下,这很少是一种限制。
9.3使用任务通知
任务通知API选项
任务通知是一项非常强大的功能,通常可以用来代替二进制信号量,计数信号量,事件组,有时甚至是队列。 通过使用xTaskNotify()API函数发送任务通知,并使用xTaskNotifyWait()API函数接收任务通知,可以实现广泛的使用场景。
但是,在大多数情况下,不需要xTaskNotify()和xTaskNotifyWait()API函数提供的完全灵活性,并且更简单的函数就足够了。 因此,提供xTaskNotifyGive()API函数作为xTaskNotify()的一种更简单但不太灵活的替代方法,并且提供ulTaskNotifyTake()API函数作为xTaskNotifyWait()的一种更简单但不太灵活的替代方法。
xTaskNotifyGive()API函数
xTaskNotifyGive()直接向任务发送通知,并增加(添加一个)接收任务的通知值。 调用xTaskNotifyGive()会将接收任务的通知状态设置为“挂起”(如果尚未挂起)。
提供了xTaskNotifyGive()1 API函数,以使任务通知的重量更轻,并且可以更快地替代二进制或计数信号量。
Parameter Name/ Returned Value | Description |
---|---|
xTaskToNotify | 将通知发送到的任务的句柄-有关获取任务句柄的信息,请参阅xTaskCreate()API函数的pxCreatedTask参数。 |
Returned value | xTaskNotifyGive()是调用xTaskNotify()的宏。 设置宏传递给xTaskNotify()的参数,以使pdPASS是唯一可能的返回值。 本书稍后将介绍xTaskNotify()。 |