freertos的任务通知

使用FreeRTOS的应用程序被构造为一组独立的任务,这些自主任务很可能必须相互通信,以便共同提供有用的系统功能。

通过中间对象进行通信

这本书已经描述了任务之间相互沟通的各种方式。到目前为止描述的方法需要创建一个通信对象。
通信对象的示例包括队列、事件组和各种不同类型的信号量。

当使用通信对象时,事件和数据不会直接发送到接收任务或接收ISR,而是发送到通信对象。同样,任务和ISR从通信对象接收事件和数据,而不是直接从发送事件或数据的任务或ISR接收。如图76所示。
在这里插入图片描述

任务通知——直接到任务通信

“任务通知”允许任务与其他任务交互,并与ISR同步,而不需要单独的通信对象。通过使用任务通知,任务或ISR可以直接向接收任务发送事件。如图77所示。

在这里插入图片描述
任务通知功能是可选的。要包含任务通知功能,请在FreeRTOSConfig.h中将configUSE_task_NOTIFICATIONS设置为1。

当configUSE_TASK_NOTIFICATIONS设置为1时,每个任务都有一个“通知状态”,可以是“挂起”或“非挂起”,还有一个“通知值”,它是一个32位无符号整数。当任务收到通知时,其通知状态设置为挂起。
当任务读取其通知值时,其通知状态设置为非挂起。

任务可以在“阻塞”状态下等待通知状态变为挂起,并可选择超时。

任务通知;优点和局限性

任务通知的性能优势

使用任务通知向任务发送事件或数据比使用队列、信号量或事件组执行等效操作要快得多。

任务通知的RAM占用优势

同样,与使用队列、信号量或事件组执行等效操作相比,使用任务通知向任务发送事件或数据所需的RAM要少得多。这是因为每个通信对象(队列、信号量或事件组)在使用之前都必须创建,而启用任务通知功能的固定开销是每个任务只有8字节的RAM。

任务通知的局限性

任务通知比通信对象更快,使用的RAM更少,但任务通知不能在所有情况下使用。本节记录了无法使用任务通知的情况:

向ISR发送事件或数据
通信对象可用于将事件和数据从ISR发送到任务,以及从任务发送到ISR。

任务通知可用于将事件和数据从ISR发送到任务,但不能用于将事件或数据从任务发送到ISR。

启用多个接收任务
任何知道其句柄(可能是队列句柄、信号量句柄或事件组句柄)的任务或ISR都可以访问通信对象。任意数量的任务和ISR都可以处理发送到任何给定通信对象的事件或数据。

任务通知直接发送给接收任务,因此只能由接收通知的任务处理。然而,在实际情况下,这很少是一个限制,因为虽然通常会有多个任务和ISR发送到同一个通信对象,但很少有多个任务和ISR从同一通信对象接收。

缓冲多个数据项
队列是一个通信对象,一次可以容纳多个数据项。已发送到队列但尚未从队列接收到的数据在队列对象内缓冲。
任务通知通过更新接收任务的通知值向任务发送数据。一个任务的通知值一次只能包含一个值。

广播多个任务
事件组是一个通信对象,可用于一次向多个任务发送事件。
任务通知直接发送给接收任务,因此只能由接收任务处理。

在阻塞状态下等待发送完成
如果通信对象暂时处于无法写入更多数据或事件的状态(例如,当队列已满时,无法向队列发送更多数据),则尝试写入该对象的任务可以选择进入“阻塞”状态,等待其写入操作完成。

如果任务试图向已挂起通知的任务发送任务通知,则发送任务无法在“阻塞”状态下等待接收任务重置其通知状态。可以看出,在使用任务通知的实际情况下,这很少是一种限制。

使用任务通知

任务通知API选项

任务通知是一个非常强大的功能,通常可以用来代替二进制信号量、计数信号量、事件组,有时甚至可以代替队列。这种广泛的使用场景可以通过使用xTaskNotify()API函数发送任务通知,使用xTaskNotifyWait()API函数接收任务通知来实现

然而,在大多数情况下,不需要xTaskNotify()和xTaskNotify Wait()API函数提供的全部灵活性,更简单的函数就足够了。
因此,xTaskNotifyGivee()API函数是作为xTaskNotify()的一种更简单但灵活性较低的替代方法提供的,而ulTaskNotifyTake()API函数是作为xTaskNotifyWait()的更简单但灵活性较低的替换方法提供的。

xTaskNotifyGive() API 函数

xTaskNotifyGive()直接向任务发送通知,并将接收任务的通知值递增(加一)。如果接收任务的通知状态尚未处于挂起状态,则调用xTaskNotifyGive()将其设置为挂起状态。
xTaskNotifyGivee()API函数用于将任务通知用作二进制或计数信号量的更轻、更快的替代方案。

BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify );

xTaskToNotify
要向其发送通知的任务的句柄-有关获取任务句柄的信息,请参阅xTaskCreate()API函数的pxCreatedTask参数。

返回值
xTaskNotifyGive()是一个调用xTaskNotify()的宏。宏传递给xTaskNotify()的参数被设置为pdPASS是唯一可能的返回值。

vTaskNotifyGiveFromISR() API 函数
vTaskNotifyGiveFromISR()是xTaskNotifyGive()的一个版本,可用于中断服务例程。

void vTaskNotifyGiveFromISR( TaskHandle_t xTaskToNotify,
BaseType_t *pxHigherPriorityTaskWoken );

xTaskToNotify
要向其发送通知的任务的句柄-有关获取任务句柄的信息,请参阅xTaskCreate()API函数的pxCreatedTask参数。

pxHigherPriorityTaskWoken
如果正在向其发送通知的任务正处于“已阻塞”状态等待接收通知,则发送通知将导致任务离开“阻塞”状态。

如果调用vTaskNotifyGiveFromISR()导致任务离开“阻塞”状态,并且未阻塞的任务的优先级高于当前正在执行的任务(被中断的任务)的优先级,那么在内部,vTaskNotifyGiveFromISR()将把*pxHigherPriorityTaskWoken设置为pdTRUE。

如果vTaskNotifyGiveFromISR()将此值设置为pdTRUE,则应在退出中断之前执行上下文切换。这将确保中断直接返回到最高优先级的就绪状态任务。

与所有中断安全的API函数一样,pxHigherPriorityTaskWoken参数在使用之前必须设置为pdFALSE。

ulTaskNotifyTake() API 函数

ulTaskNotifyTake()允许任务在“阻塞”状态下等待其通知值大于零,并在返回之前递减(减一)或清除任务的通知值。

提供ulTaskNotifyTake()API函数是为了允许将任务通知用作二进制或计数信号量的更轻、更快的替代方案。

uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait );

xClearCountOnExit
如果xClearCountOnExit设置为pdTRUE,则在对ulTaskNotifyTake()的调用返回之前,调用任务的通知值将被清除为零。
如果xClearCountOnExit设置为pdFALSE,并且调用任务的通知值大于零,则在对ulTaskNotifyTake()的调用返回之前,调用任务的报告值将被递减。

xTicksToWait
调用任务应保持在“阻塞”状态以等待其通知值大于零的最长时间。

块时间以滴答周期指定,因此它表示的绝对时间取决于滴答频率。宏pdMS_TO_TICKS()可用于将以毫秒为单位指定的时间转换为以刻度为单位的时间。

将xTicksToWait设置为portMAX_DELAY将导致该任务
如果在FreeRTOSConfig.h中将INCLUDE_vTaskSuspend设置为1,则可以无限期等待(不超时)。

返回值
返回值是调用任务在清除为零或递减之前的通知值,由xClearCountOnExit参数的值指定。

如果指定了块时间(xTicksToWait不为零),并且返回值不为零,则调用任务可能被置于“已阻塞”状态,等待其通知值大于零,并且其通知值在块时间到期之前被更新。

如果指定了块时间(xTicksToWait不为零),并且返回值为零,则调用任务被置于“已阻塞”状态,等待其通知值大于零,但指定的块时间在此之前已过期。

例24。使用任务通知代替信号量,方法1
使用二进制信号量从中断服务例程中解锁任务,从而有效地将任务与中断同步。此示例复制了这个功能,但使用直接到任务通知来代替二进制信号量。

清单148显示了与中断同步的任务的实现。对xSaphoreTake()的调用已被代替为ulTaskNotifyTake()。

ulTaskNotifyTake()xClearCountOnExit参数设置为pdTRUE,这导致在ulTaskNotifyTake()返回之前,接收任务的通知值被清除为零。因此,有必要处理每次呼叫之间已经可用的所有事件
ulTaskNotifyTake()。之前的示例由于使用了二进制信号量,因此必须从硬件中确定挂起事件的数量,这并不总是可行的。在示例24中,从ulTaskNotifyTake()返回挂起事件的数量。

在调用ulTaskNotifyTake之间发生的中断事件被锁定在任务的通知值中,如果调用任务已经有待处理的通知,则对ulTaskNotifyTake()的调用将立即返回。

在这里插入图片描述

用于生成软件中断的周期性任务在中断生成之前打印一条消息,并在中断生成之后再次打印。这允许在生成的输出中观察执行顺序。
清单149显示了中断处理程序。除了直接向延迟中断处理的任务发送通知外,几乎没有做什么。

在这里插入图片描述

执行示例24时产生的输出如图78所示。正如预期的那样,它与实施例16时产生的结果相同。vHandlerTask()在中断生成后立即进入运行状态,因此任务的输出会拆分周期性任务产生的输出。图79提供了进一步的解释。

在这里插入图片描述

示例25。使用任务通知代替信号量,方法2

在示例24中,ulTaskNotifyTake()xClearOnExit参数设置为pdTRUE。示例25稍微修改了示例24,以演示当ulTaskNotifyTake()xClearOnExit参数设置为pdFALSE时的行为。

当xClearOneExit为pdFALSE时,调用ulTaskNotifyTake()只会减少(减少一)调用任务的通知值,而不是将其清除为零。因此,通知计数是已发生的事件数与已处理的事件数之间的差值。这使得vHandlerTask()的结构可以通过两种方式简化:

1.等待处理的事件数保存在通知值中,因此不需要保存在局部变量中。
2.每次调用ulTaskNotifyTake()之间只需要处理一个事件。

示例25中使用的vHandlerTask()的实现如清单150所示。

在这里插入图片描述

出于演示目的,中断服务例程也被修改为每个中断发送多个任务通知,从而模拟高频发生的多个中断。示例25中使用的中断服务例程的实现如清单151所示。

在这里插入图片描述
执行示例25时产生的输出如图80所示。可以看出,vHandlerTask()每次生成中断时都会处理所有三个事件。在这里插入图片描述
在这里插入图片描述

xTaskNotify()和xTaskNotifyFromISR()API函数

xTaskNotify()是xTaskNotifyGive()的一个功能更强大的版本,可用于通过以下任何一种方式更新接收任务的通知值:

1 递增(加一)接收任务的通知值,在这种情况下,xTaskNotify()等效于xTaskNotifyGive()。

2 在接收任务的通知值中设置一个或多个位。这允许将任务的通知值用作事件组的更轻、更快的替代方案。

3 在接收任务的通知值中写入一个全新的数字,但前提是接收任务自上次更新以来已读取其通知值。这允许任务的通知值提供与长度为1的队列提供的功能类似的功能。

4 在接收任务的通知值中写入一个全新的数字,即使接收任务自上次更新以来没有读取其通知值。这允许任务的通知值提供与xQueueOverwrite()API函数提供的功能类似的功能。由此产生的行为有时被称为“邮箱”。

xTaskNotify()比xTaskNotifyGive()更灵活、更强大,而且由于这种额外的灵活性和功能,使用起来也有点复杂。
xTaskNotifyFromISR()是xTaskNotify()的一个版本,可用于中断服务例程,因此有一个额外的pxHigherPriorityTaskWoken参数
如果接收任务的通知状态尚未处于挂起状态,则调用xTaskNotify()将始终将其设置为挂起状态。

BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify,
uint32_t ulValue,
eNotifyAction eAction );
BaseType_t xTaskNotifyFromISR( TaskHandle_t xTaskToNotify,
uint32_t ulValue,
eNotifyAction eAction,
BaseType_t *pxHigherPriorityTaskWoken );

xTaskToNotify
要向其发送通知的任务的句柄-有关获取任务句柄的信息,请参阅xTaskCreate()API函数的pxCreatedTask参数。

ulValue
ulValue的使用方式取决于eNtifyAction值。

eNotifyAction
一种枚举类型,指定如何更新接收任务的通知值。

返回值
xTaskNotify()将返回pdPASS但有一种情况除外。

eNoAction
接收任务的通知状态设置为挂起,而其通知值不会更新。xTaskNotify() ulValue 参数不被使用。
eNoAction操作允许将任务通知用作二进制信号量的更快、更轻的替代方案。

eSetBits
接收任务的通知值与xTaskNotify()ulValue参数中传递的值按位或进行运算。例如,如果ulValue设置为0x01,则接收任务的通知值中将设置位0。再举一个例子,如果ulValue为0x06(二进制0110),则接收任务的通知值中将设置位1和位2。

eSetBits操作允许将任务通知用作事件组的更快、更轻的替代方案。

eIncrement
接收任务通知的值在增加。xTaskNotify() ulValue 参数不被使用。
eIncrement 操作允许任务通知用作二值或计数信号量的更快、更轻的替代方案,等于更简单的 xTaskNotifyGive() API 函数。

eSetValueWithoutOverwrite
如果接收任务有一个通知在xTaskNotify() 调用前挂起,没有操作会发生并且xTaskNotify() 将返回pdFAIL

如果接收任务没有有一个通知在xTaskNotify() 调用前挂起,接收任务通知值在xTaskNotify() ulValue参数中被设置为passed。

eSetValueWithOverwrite
接收任务通知值在xTaskNotify() ulValue参数中被设置为passed。不管接收任务在xTaskNotify() 被调用前是否有一个通知挂起。

xTaskNotifyWait()API函数

xTaskNotifyWait()是ulTaskNotifyTake()的一个功能更强大的版本。它允许任务等待调用任务的通知状态变为挂起,如果它还没有挂起,则可以选择超时。xTaskNotifyWait()提供了在进入函数和退出函数时清除调用任务通知值中的位的选项。

BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry,
uint32_t ulBitsToClearOnExit,
uint32_t *pulNotificationValue,
TickType_t xTicksToWait );

ulBitsToClearOnEntry
如果调用任务在调用xTaskNotifyWait()之前没有待处理的通知,则ulBitsToClearOnEntry中设置的任何位都将在进入函数时在任务的通知值中清除。

例如,如果ulBitsToClearOnEntry为0x01,则任务通知值的位0将被清除。再举一个例子,将ulBitsToClearOneEntry设置为0xffffff(ULONG_MAX)将清除任务通知值中的所有位,有效地将该值清除为0。

ulBitsToClearOnExit
如果调用任务退出xTaskNotifyWait()是因为它收到了通知,或者因为在调用xTaskNotifyWait()时它已经有一个待处理的通知,那么在任务退出xTask NotifyWait)函数之前,ulBitsToClearOnExit中设置的任何位都将在任务的通知值中清除。

任务的通知值保存在*pulNotificationValue中后,这些位将被清除。

例如,如果ulBitsToClearOnExit为0x03,则在函数退出之前,任务通知值的位0和位1将被清除

将ulBitsToClearOneExit设置为0xffffff(ULONG_MAX)将清除任务通知值中的所有位,有效地将该值清除为0。

pulNotificationValue
用于传递任务的通知值。复制到*pulNotificationValue的值是任务的通知值,与由于ulBitsToClearOnExit设置而清除任何位之前的值相同。

pulNotificationValue是一个可选参数,如果不需要,可以设置为NULL。

xTicksToWait
调用任务应保持在“阻塞”状态以等待其通知状态变为挂起的最长时间。

块时间以滴答周期指定,因此它表示的绝对时间取决于滴答频率。宏pdMS_TO_TICKS()可用于将以毫秒为单位指定的时间转换为以刻度为单位的时间。

将xTicksToWait设置为portMAX_DELAY将导致该任务
如果在FreeRTOSConfig.h中将INCLUDE_vTaskSuspend设置为1,则可以无限期等待(不超时)。

返回值
有两种可能的返回值:
1.pdTRUE
这表示xTaskNotifyWait()返回是因为收到了通知,或者是因为调用xTaskNotifyWait()时调用任务已经有一个待处理的通知。

如果指定了阻塞时间(xTicksToWait不为零),则调用任务可能被置于“阻塞”状态,等待其通知状态变为挂起,但在阻塞时间到期之前,其通知状态被设置为挂起。

2.pdFALSE
这表示xTaskNotifyWait()返回时,调用任务没有收到任务通知。
如果xTicksToWait不为零,则调用任务将保持在“已阻塞”状态,等待其通知状态变为挂起,但指定的阻塞时间在此之前已过期。

外围设备驱动程序中使用的任务通知:UART示例

外围驱动程序库提供在硬件接口上执行常见操作的功能。通常提供此类库的外围设备的示例包括通用异步接收器和发射器(UART)、串行外围接口(SPI)端口、模数转换器(ADC)和以太网端口。此类库通常提供的功能示例包括初始化外围设备、向外围设备发送数据以及从外围设备接收数据的功能。

外围设备上的某些操作需要相对较长的时间才能完成。此类操作的示例包括高精度ADC转换和在UART上传输大数据包。在这些情况下,可以实现驱动程序库功能来轮询(重复读取)外围设备的状态寄存器,以确定操作何时完成。然而,以这种方式进行轮询几乎总是浪费时间,因为它利用了处理器100%的时间,而没有执行生产性处理。在多任务系统中,浪费尤其昂贵,因为轮询外围设备的任务可能会阻塞执行优先级较低的任务,而该任务确实需要进行生产性处理。

为了避免浪费处理时间的可能性,一个高效的RTOS感知设备驱动程序应该是中断驱动的,并为启动长时间操作的任务提供在阻塞状态下等待操作完成的选项。这样,在执行长时间操作的任务处于“阻塞”状态时,可以执行优先级较低的任务,并且除非任务能够有效地使用处理时间,否则任何任务都不会使用处理时间。

RTOS感知驱动程序库的常见做法是使用二进制信号量将任务置于阻塞状态。该技术由清单154中所示的伪代码演示,该伪代码提供了在UART端口上传输数据的RTOS感知库函数的概要。在清单154中:

xUART是一种描述UART外围设备并保存状态信息的结构。
结构的xTxSemaphore成员是SemaphoreHandle_t类型的变量。
假设信号量已经创建。

xUART_Send()函数不包含任何互斥逻辑。如果多个任务将使用xUART_Send()函数,则应用程序编写者必须在应用程序本身内管理互斥。例如,在调用xUART_Send()之前,可能需要一个任务来获取互斥体。

xSemaphoreTake()API函数用于在启动UART传输后将调用任务置于阻塞状态。

xSemaphoreGiveFromISR()API函数用于在传输完成后,即UART外围设备的传输结束中断服务例程执行时,将任务从阻塞状态中移除。

在这里插入图片描述

清单154中演示的技术是完全可行的,而且确实是常见的做法,但它有一些缺点:

该库使用多个信号量,这增加了其RAM占用空间。
信号量在创建之前无法使用,因此使用信号量的库在显式初始化之前无法使用。

信号量是适用于广泛用例的通用对象;它们包括允许任意数量的任务在阻塞状态下等待信号量可用的逻辑,以及在信号量确实可用时选择(以确定性的方式)从阻塞状态中删除哪个任务的逻辑。
执行该逻辑需要有限的时间,在清单154所示的场景中,处理开销是不必要的,在任何给定时间都不能有多个任务等待信号量。

清单155演示了如何通过使用任务通知代替二进制信号量来避免这些缺点。
注意:如果库使用任务通知,则库的文档必须明确说明调用库函数可以更改调用任务的通知状态和通知值。

在清单155中:
xUART结构的xTxSemaphore成员已被xTaskToNotify成员替换。xTaskToNotify是TaskHandle_t类型的变量,用于保存等待UART操作完成的任务的句柄。

xTaskGetCurrentTaskHandle()FreeRTOS API函数用于获取处于运行状态的任务的句柄。

该库不创建任何FreeRTOS对象,因此不会产生RAM开销,也不需要显式初始化。

任务通知直接发送给正在等待UART操作完成的任务,因此不会执行不必要的逻辑。

xUART结构的xTaskToNotify成员可以从任务和中断服务例程访问,需要考虑处理器将如何更新其值:

如果xTaskToNotify是通过单个内存写入操作更新的,那么它可以在关键部分之外进行更新,如清单155所示。如果xTaskToNotify是一个32位变量(TaskHandle_t是一种32位类型),并且运行FreeRTOS的处理器是32位处理器,则会出现这种情况。

如果需要多个内存写入操作来更新xTaskToNotify,则xTaskToNotification只能从关键部分内更新,否则中断服务例程可能会在xTaskToNotification处于不一致状态时访问它。
如果xTaskToNotify是一个32位变量,并且运行FreeRTOS的处理器是一个16位处理器,则会出现这种情况,因为它需要两次16位内存写入操作来更新所有32位。

在内部,在FreeRTOS实现中,TaskHandle_t是一个指针,因此sizeof(TaskHandle_t)始终等于sizeof(void*)。
在这里插入图片描述
在这里插入图片描述
任务通知还可以替换接收函数中的信号量,如伪代码清单156所示,该清单提供了在UART端口上接收数据的RTOS感知库函数的概述。参考清单156:

xUART_Receive()函数不包含任何互斥逻辑。如果多个任务将使用xUART_Receive()函数,则应用程序编写者必须在应用程序本身内管理互斥。例如,在调用xUART_Receive()之前,可能需要一个任务来获取互斥体。

UART的接收中断服务例程将UART接收到的字符放入RAM缓冲区。xUART_Receive()函数从RAM缓冲区返回字符。

xUART_Receive()uxWantedBytes参数用于指定要接收的字符数。如果RAM缓冲区尚未包含所请求的数字字符,则调用任务将被置于“阻塞”状态,等待缓冲区中的字符数增加的通知。while()循环用于重复此序列,直到接收缓冲区包含请求的字符数,或者发生超时。

调用任务可能多次进入“阻塞”状态。因此,调整块时间以考虑自调用xUART_Receive()以来已经过去的时间量。这些调整确保在xUART_Receive()内花费的总时间不超过xUART结构的xRxTimeout成员指定的块时间。使用FreeRTOS vTaskSetTimeOutState()和xTaskCheckForTimeOut()辅助函数调整块时间。
在这里插入图片描述
在这里插入图片描述

外围设备驱动程序中使用的任务通知:ADC示例

上一节演示了如何使用vTaskNotifyGiveFromISR()从中断向任务发送任务通知。vTaskNotifyGiveFromISR()是一个使用简单的函数,但其功能有限;它只能将任务通知作为无值事件发送,不能发送数据。本节演示如何使用xTaskNotifyFromISR()发送带有任务通知事件的数据。清单157所示的伪代码演示了该技术,它提供了模数转换器(ADC)的RTOS感知中断服务例程的概述。在清单157中:

假设ADC转换至少每50毫秒启动一次。

ADC_ConversionEndISR()是ADC转换结束中断的中断服务例程,该中断是每次有新的ADC值可用时执行的中断。

vADCTask()执行的任务处理ADC生成的每个值。假设创建任务时,任务的句柄存储在xADCTaskToNotify中。

ADC_ConversionEndISR()使用xTaskNotifyFromISR(),将eAction参数设置为eSetValueWithoutOverwrite,向vADCTask()任务发送任务通知,并将ADC转换的结果写入任务的通知值

vADCTask()任务使用xTaskNotifyWait()等待新ADC值可用的通知,并从其通知值中检索ADC转换的结果。

在这里插入图片描述在这里插入图片描述

直接在应用程序中使用的任务通知

本节通过演示任务通知在包括以下功能的假设应用程序中的使用,加强了任务通知的功能:
1.应用程序通过慢速互联网连接进行通信,以向远程数据服务器发送数据和从远程数据服务器请求数据。从这里开始,远程数据服务器被称为云服务器。
2.在向云服务器请求数据后,请求任务必须在“阻塞”状态下等待接收所请求的数据。
3.向云服务器发送数据后,发送任务必须在“阻塞”状态下等待云服务器正确接收数据的确认。

软件设计示意图如图81所示。在图81中:

处理到云服务器的多个互联网连接的复杂性被封装在一个FreeRTOS任务中。该任务在FreeRTOS应用程序中充当代理服务器,称为服务器任务。

应用程序任务通过调用CloudRead()从云服务器读取数据。CloudRead()不直接与云服务器通信,而是将读取请求发送到队列上的服务器任务,并从服务器任务接收所请求的数据作为任务通知。

应用程序任务通过调用CloudWrite()将日期写入云服务器。CloudWrite()不直接与云服务器通信,而是将写请求发送到队列上的服务器任务,并从服务器任务接收写操作的结果作为任务通知。

CloudRead()和CloudWrite()函数发送给服务器任务的结构如清单158所示。

在这里插入图片描述
在这里插入图片描述

CloudRead()的伪代码如清单159所示。该函数将其请求发送到服务器任务,然后调用xTaskNotifyWait()在Blocked状态下等待,直到收到请求的数据可用的通知。
显示服务器任务如何管理读取请求的伪代码如清单160所示。
当从云服务器接收到数据时,服务器任务会取消阻塞应用程序任务,并通过调用xTaskNotify()将eAction参数设置为eSetValueWithOverwrite,将接收到的数据发送给应用程序任务。
清单160显示了一个简化的场景,因为它假设GetCloudData()不必等待从云服务器获取值。

在这里插入图片描述
在这里插入图片描述
CloudWrite()的伪代码如清单161所示。为了演示的目的,CloudWrite()返回一个位状态代码,其中状态代码中的每个位都被赋予了唯一的含义。清单161顶部的#define语句显示了四个示例状态位。

该任务清除四个状态位,将其请求发送到服务器任务,然后调用xTaskNotifyWait()在阻塞状态下等待状态通知。

在这里插入图片描述
在这里插入图片描述

演示服务器任务如何管理写请求的伪代码如清单162所示。当数据被发送到云服务器时,服务器任务会取消阻塞应用程序任务,并通过调用xTaskNotify()并将eAction参数设置为eSetBits,将位状态代码发送给应用程序任务。在接收任务的通知值中,只有CLOUD_WRITE_ATUBIT_MASK常量定义的位可以更改,因此接收任务可以将其通知值中的其他位用于其他目的。

清单162显示了一个简化的场景,因为它假设SetCloudData()不必等待从远程云服务器获得确认。

在这里插入图片描述

上一篇:101. UE5 GAS RPG 实现范围技能奥术爆发表现


下一篇:磁盘的分区、格式化、检验与挂载-磁盘挂载