FreeRTOS--任务通知
示例源码基于FreeRTOS V9.0.0
任务通知
1. 概述
任务通知是也是RTOS中任务通信的一种方式,区别于队列,信号量,事件组等,它不使用额外的结构体作为通信内容;
基于任务通知,可以实现轻量级的队列(长度为1)、邮箱(覆盖的队列)、计数型和二值信号量、事件组;
2. 特性
2.1 劣势
- 仅能发送给任务,不能发送给ISR。发送方可以为任务和ISR,接收方只能为任务;
- 仅能发送给单个任务,不能广播,而事件组可以实现广播通知;
- 无法缓存数据,而队列可以缓存;
- 数据只能任务独享,即只能通知特定任务,其他任务无法访问通知值;
- 发送受阻时无法等待,只能失败退出;
2.2 优势
- 相比于队列、信号量、事件组,其效率更高;
- 占用内存更小,它不创建单独的结构体或内存块去缓存数据,而是仅使用任务控制块TCB中的通知值和通知状态;
3. 代码实现
3.1 通知值和通知状态
typedef struct tskTaskControlBlock{
...
#if( configUSE_TASK_NOTIFICATIONS == 1 )
volatile uint32_t ulNotifiedValue; // 通知值
volatile uint8_t ucNotifyState; // 通知状态
#endif
...
}tskTCB;
typedef tskTCB TCB_t;
任务通知的实现基于TCB中的ulNotifiedValue和ucNotifyState,使用任务通知,需要启用宏configUSE_TASK_NOTIFICATIONS。通知状态包括以下几种:
/* Values that can be assigned to the ucNotifyState member of the TCB. */
#define taskNOT_WAITING_NOTIFICATION ( ( uint8_t ) 0 ) // 初始状态,非等待
#define taskWAITING_NOTIFICATION ( ( uint8_t ) 1 ) // 等待通知,阻塞态
#define taskNOTIFICATION_RECEIVED ( ( uint8_t ) 2 ) // 收到通知
3.2 接口
任务通知有两套函数,简化版和专业版,简化版也是基于专业版实现的。
简化版 | 专业版 | |
---|---|---|
发出通知 | xTaskNotifyGive vTaskNotifyGiveFromISR | xTaskNotify xTaskNotifyAndQuery xTaskNotifyFromISR xTaskNotifyAndQueryFromISR |
取出通知 | ulTaskNotifyTake | xTaskNotifyWait |
3.2.1 xTaskNotify
BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue ) PRIVILEGED_FUNCTION;
#define xTaskNotify( xTaskToNotify, ulValue, eAction ) xTaskGenericNotify( ( xTaskToNotify ), ( ulValue ), ( eAction ), NULL )
#define xTaskNotifyAndQuery( xTaskToNotify, ulValue, eAction, pulPreviousNotifyValue ) xTaskGenericNotify( ( xTaskToNotify ), ( ulValue ), ( eAction ), ( pulPreviousNotifyValue ) )
xTaskNotify和xTaskNotifyAndQuery原型为xTaskGenericNotify,区别在于参数pulPreviousNotificationValue,xTaskNotify为NULL,xTaskNotifyAndQuery则提供了出参。
xTaskNotify和xTaskNotifyAndQuery在任务中使用,用于发送通知。
#if( configUSE_TASK_NOTIFICATIONS == 1 )
BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue )
{
TCB_t * pxTCB;
BaseType_t xReturn = pdPASS;
uint8_t ucOriginalNotifyState;
configASSERT( xTaskToNotify );
pxTCB = ( TCB_t * ) xTaskToNotify;
taskENTER_CRITICAL();
{
if( pulPreviousNotificationValue != NULL )
{
*pulPreviousNotificationValue = pxTCB->ulNotifiedValue;
}
ucOriginalNotifyState = pxTCB->ucNotifyState;
pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED;
switch( eAction )
{
case eSetBits :
pxTCB->ulNotifiedValue |= ulValue;
break;
case eIncrement :
( pxTCB->ulNotifiedValue )++;
break;
case eSetValueWithOverwrite :
pxTCB->ulNotifiedValue = ulValue;
break;
case eSetValueWithoutOverwrite :
if( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED )
{
pxTCB->ulNotifiedValue = ulValue;
}
else
{
/* The value could not be written to the task. */
xReturn = pdFAIL;
}
break;
case eNoAction:
/* The task is being notified without its notify value being
updated. */
break;
}
traceTASK_NOTIFY();
/* If the task is in the blocked state specifically to wait for a
notification then unblock it now. */
if( ucOriginalNotifyState == taskWAITING_NOTIFICATION )
{
( void ) uxListRemove( &( pxTCB->xStateListItem ) );
prvAddTaskToReadyList( pxTCB );
/* The task should not have been on an event list. */
configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL );
#if( configUSE_TICKLESS_IDLE != 0 )
{
/* If a task is blocked waiting for a notification then
xNextTaskUnblockTime might be set to the blocked task's time
out time. If the task is unblocked for a reason other than
a timeout xNextTaskUnblockTime is normally left unchanged,
because it will automatically get reset to a new value when
the tick count equals xNextTaskUnblockTime. However if
tickless idling is used it might be more important to enter
sleep mode at the earliest possible time - so reset
xNextTaskUnblockTime here to ensure it is updated at the
earliest possible time. */
prvResetNextTaskUnblockTime();
}
#endif
if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
{
/* The notified task has a priority above the currently
executing task so a yield is required. */
taskYIELD_IF_USING_PREEMPTION();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
taskEXIT_CRITICAL();
return xReturn;
}
#endif /* configUSE_TASK_NOTIFICATIONS */
代码分析:
- 进入临界区,关闭中断;
- 如果pulPreviousNotificationValue != NULL,则将通知值pxTCB->ulNotifiedValue作为赋给*pulPreviousNotificationValue,作为出参,此时的通知值是上一次的,修改前的。
- 先备份通知状态,再修改通知状态为taskNOTIFICATION_RECEIVED,标识已经接收到通知了;
- 根据参数eAction对通知值做如下修改:
- eSetBits:用于设置对应比特位,设置值为ulValue,基于此实现轻量级事件组;
- eIncrement:累加通知值,基于此实现轻量级信号量;
- eSetValueWithOverwrite:覆盖通知值,将其设置为ulValue。基于此实现轻量级邮箱;
- eSetValueWithoutOverwrite:仅在通知值被读取后才设置,设置值为ulValue,否则不修改通知值,标记返回失败,基于此实现轻量级的长度为1的队列;
- eNoAction:什么都不做;
- 如果任务原先是在等待通知的,即阻塞态,那么将其加入就绪列表,待唤醒执行。
- 出临界区,开中断;
参数ulValue依赖于参数eAction,仅当其为eSetBits、eSetValueWithOverwrite和eSetValueWithoutOverwrite才有效;
函数xTaskGenericNotify仅在eAction为eSetValueWithoutOverwrite且通知值尚未读出时才返回失败pdFAIL,其他情况均返回成功pdPASS;
3.2.2 xTaskNotifyFromISR
BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;
#define xTaskNotifyFromISR( xTaskToNotify, ulValue, eAction, pxHigherPriorityTaskWoken ) xTaskGenericNotifyFromISR( ( xTaskToNotify ), ( ulValue ), ( eAction ), NULL, ( pxHigherPriorityTaskWoken ) )
#define xTaskNotifyAndQueryFromISR( xTaskToNotify, ulValue, eAction, pulPreviousNotificationValue, pxHigherPriorityTaskWoken ) xTaskGenericNotifyFromISR( ( xTaskToNotify ), ( ulValue ), ( eAction ), ( pulPreviousNotificationValue ), ( pxHigherPriorityTaskWoken ) )
xTaskNotifyFromISR和xTaskNotifyAndQueryFromISR原型为xTaskGenericNotifyFromISR,区别在于参数pulPreviousNotificationValue,xTaskNotifyFromISR为NULL,xTaskNotifyAndQueryFromISR则提供了出参。
xTaskNotifyFromISR和xTaskNotifyAndQueryFromISR在中断上下文中使用,用于发送通知。
#if( configUSE_TASK_NOTIFICATIONS == 1 )
BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue, BaseType_t *pxHigherPriorityTaskWoken )
{
TCB_t * pxTCB;
uint8_t ucOriginalNotifyState;
BaseType_t xReturn = pdPASS;
UBaseType_t uxSavedInterruptStatus;
configASSERT( xTaskToNotify );
/* RTOS ports that support interrupt nesting have the concept of a
maximum system call (or maximum API call) interrupt priority.
Interrupts that are above the maximum system call priority are keep
permanently enabled, even when the RTOS kernel is in a critical section,
but cannot make any calls to FreeRTOS API functions. If configASSERT()
is defined in FreeRTOSConfig.h then
portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
failure if a FreeRTOS API function is called from an interrupt that has
been assigned a priority above the configured maximum system call
priority. Only FreeRTOS functions that end in FromISR can be called
from interrupts that have been assigned a priority at or (logically)
below the maximum system call interrupt priority. FreeRTOS maintains a
separate interrupt safe API to ensure interrupt entry is as fast and as
simple as possible. More information (albeit Cortex-M specific) is
provided on the following link:
http://www.freertos.org/RTOS-Cortex-M3-M4.html */
portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
pxTCB = ( TCB_t * ) xTaskToNotify;
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
{
if( pulPreviousNotificationValue != NULL )
{
*pulPreviousNotificationValue = pxTCB->ulNotifiedValue;
}
ucOriginalNotifyState = pxTCB->ucNotifyState;
pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED;
switch( eAction )
{
case eSetBits :
pxTCB->ulNotifiedValue |= ulValue;
break;
case eIncrement :
( pxTCB->ulNotifiedValue )++;
break;
case eSetValueWithOverwrite :
pxTCB->ulNotifiedValue = ulValue;
break;
case eSetValueWithoutOverwrite :
if( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED )
{
pxTCB->ulNotifiedValue = ulValue;
}
else
{
/* The value could not be written to the task. */
xReturn = pdFAIL;
}
break;
case eNoAction :
/* The task is being notified without its notify value being
updated. */
break;
}
traceTASK_NOTIFY_FROM_ISR();
/* If the task is in the blocked state specifically to wait for a
notification then unblock it now. */
if( ucOriginalNotifyState == taskWAITING_NOTIFICATION )
{
/* The task should not have been on an event list. */
configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL );
if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
{
( void ) uxListRemove( &( pxTCB->xStateListItem ) );
prvAddTaskToReadyList( pxTCB );
}
else
{
/* The delayed and ready lists cannot be accessed, so hold
this task pending until the scheduler is resumed. */
vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
}
if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
{
/* The notified task has a priority above the currently
executing task so a yield is required. */
if( pxHigherPriorityTaskWoken != NULL )
{
*pxHigherPriorityTaskWoken = pdTRUE;
}
else
{
/* Mark that a yield is pending in case the user is not
using the "xHigherPriorityTaskWoken" parameter to an ISR
safe FreeRTOS function. */
xYieldPending = pdTRUE;
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
return xReturn;
}
#endif /* configUSE_TASK_NOTIFICATIONS */
代码分析:
- 如果pulPreviousNotificationValue != NULL,则将通知值pxTCB->ulNotifiedValue作为赋给*pulPreviousNotificationValue,作为出参,此时的通知值是上一次的,修改前的。
- 先备份通知状态,再修改通知状态为taskNOTIFICATION_RECEIVED,标识已经接收到通知了;
- 根据参数eAction对通知值做相应修改,同xTaskGenericNotify;
- 如果任务原先是在等待通知的,即阻塞态,那么:
- 调度器没有挂起,则将任务加入就绪列表(ready list),等待唤醒执行;
- 调度器挂起,则将任务加入待就绪列表(pending ready list);
- 如果任务优先级高于当前任务,当pxHigherPriorityTaskWoken非空时,置其为pdTRUE,标识需要任务切换,否则将全局变量xYieldPending置为pdTRUE;
xTaskGenericNotifyFromISR和xTaskGenericNotify的处理大致是相同的,区别在于ISR的接口,在设置完通知值准备唤醒任务时,需要考虑调度器是否挂起,以决定是加入ready list还是pending ready list。同时,高优先级任务获得通知时,ISR不直接让步切换,而是设置标志位;
3.2.3 xTaskNotifyWait
#if( configUSE_TASK_NOTIFICATIONS == 1 )
BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait )
{
BaseType_t xReturn;
taskENTER_CRITICAL();
{
/* Only block if a notification is not already pending. */
if( pxCurrentTCB->ucNotifyState != taskNOTIFICATION_RECEIVED )
{
/* Clear bits in the task's notification value as bits may get
set by the notifying task or interrupt. This can be used to
clear the value to zero. */
pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnEntry;
/* Mark this task as waiting for a notification. */
pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION;
if( xTicksToWait > ( TickType_t ) 0 )
{
prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
traceTASK_NOTIFY_WAIT_BLOCK();
/* All ports are written to allow a yield in a critical
section (some will yield immediately, others wait until the
critical section exits) - but it is not something that
application code should ever do. */
portYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
taskEXIT_CRITICAL();
taskENTER_CRITICAL();
{
traceTASK_NOTIFY_WAIT();
if( pulNotificationValue != NULL )
{
/* Output the current notification value, which may or may not
have changed. */
*pulNotificationValue = pxCurrentTCB->ulNotifiedValue;
}
/* If ucNotifyValue is set then either the task never entered the
blocked state (because a notification was already pending) or the
task unblocked because of a notification. Otherwise the task
unblocked because of a timeout. */
if( pxCurrentTCB->ucNotifyState == taskWAITING_NOTIFICATION )
{
/* A notification was not received. */
xReturn = pdFALSE;
}
else
{
/* A notification was already pending or a notification was
received while the task was waiting. */
pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnExit;
xReturn = pdTRUE;
}
pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
}
taskEXIT_CRITICAL();
return xReturn;
}
#endif /* configUSE_TASK_NOTIFICATIONS */
xTaskNotifyWait用于任务取出通知。
代码分析:
- 进临界区,关闭中断;
- 判断通知状态,如果不是等待通知,则在切换为等待通知状态前需要做如下工作:
- 根据参数ulBitsToClearOnEntry将通知值相应比特位清0;
- 设置通知状态为taskWAITING_NOTIFICATION,标识正在等待通知;
- 如果参数xTicksToWait>0,代表要阻塞等待,则将调用prvAddCurrentTaskToDelayedList将任务加入delay列表,并主动让步切换任务,任务进入阻塞态;
- 出临界区,开中断;
- 进临界去,关闭中断(到这里,要么任务收到通知被唤醒,要么阻塞时间超时唤醒,要么是非阻塞的接口调用);
- 如果出参pulNotificationValue非空,则将通知值赋给*pulNotificationValue;
- 判断通知状态:
- 如果通知状态为taskWAITING_NOTIFICATION,表示任务没有收到通知(阻塞时间到超时退出,或者非阻塞),标记返回值为pdFALSE;
- 否则(收到了通知,或者任务已经pending?),根据参数ulBitsToClearOnExit将通知值的相应比特位清0;
- 设置通知状态为taskNOT_WAITING_NOTIFICATION;
- 退出临界区,开中断;
xTaskNotifyWait可以根据参数ulBitsToClearOnEntry在等待通知前重置某些比特位,也可以根据参数ulBitsToClearOnExit在收到通知后重置某些比特位。通知值根据出参pulNotificationValue返回。
3.2.4 xTaskNotifyGive
#define xTaskNotifyGive( xTaskToNotify ) xTaskGenericNotify( ( xTaskToNotify ), ( 0 ), eIncrement, NULL )
xTaskNotifyGive的原型也是xTaskGenericNotify,同xTaskNotify。它也是用于发送通知。
xTaskNotifyGive与xTaskNotify区别在于,xTaskNotifyGive限定了eAction为eIncrement,ulValue为0(当eAction为eIncrement时,该值无用)。xTaskNotifyGive是xTaskNotify的轻量型信号量简化版接口。
3.2.5 vTaskNotifyGiveFromISR
#if( configUSE_TASK_NOTIFICATIONS == 1 )
void vTaskNotifyGiveFromISR( TaskHandle_t xTaskToNotify, BaseType_t *pxHigherPriorityTaskWoken )
{
TCB_t * pxTCB;
uint8_t ucOriginalNotifyState;
UBaseType_t uxSavedInterruptStatus;
configASSERT( xTaskToNotify );
/* RTOS ports that support interrupt nesting have the concept of a
maximum system call (or maximum API call) interrupt priority.
Interrupts that are above the maximum system call priority are keep
permanently enabled, even when the RTOS kernel is in a critical section,
but cannot make any calls to FreeRTOS API functions. If configASSERT()
is defined in FreeRTOSConfig.h then
portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
failure if a FreeRTOS API function is called from an interrupt that has
been assigned a priority above the configured maximum system call
priority. Only FreeRTOS functions that end in FromISR can be called
from interrupts that have been assigned a priority at or (logically)
below the maximum system call interrupt priority. FreeRTOS maintains a
separate interrupt safe API to ensure interrupt entry is as fast and as
simple as possible. More information (albeit Cortex-M specific) is
provided on the following link:
http://www.freertos.org/RTOS-Cortex-M3-M4.html */
portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
pxTCB = ( TCB_t * ) xTaskToNotify;
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
{
ucOriginalNotifyState = pxTCB->ucNotifyState;
pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED;
/* 'Giving' is equivalent to incrementing a count in a counting
semaphore. */
( pxTCB->ulNotifiedValue )++;
traceTASK_NOTIFY_GIVE_FROM_ISR();
/* If the task is in the blocked state specifically to wait for a
notification then unblock it now. */
if( ucOriginalNotifyState == taskWAITING_NOTIFICATION )
{
/* The task should not have been on an event list. */
configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL );
if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
{
( void ) uxListRemove( &( pxTCB->xStateListItem ) );
prvAddTaskToReadyList( pxTCB );
}
else
{
/* The delayed and ready lists cannot be accessed, so hold
this task pending until the scheduler is resumed. */
vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
}
if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
{
/* The notified task has a priority above the currently
executing task so a yield is required. */
if( pxHigherPriorityTaskWoken != NULL )
{
*pxHigherPriorityTaskWoken = pdTRUE;
}
else
{
/* Mark that a yield is pending in case the user is not
using the "xHigherPriorityTaskWoken" parameter in an ISR
safe FreeRTOS function. */
xYieldPending = pdTRUE;
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
}
#endif /* configUSE_TASK_NOTIFICATIONS */
vTaskNotifyGiveFromISR与xTaskGenericNotifyFromISR类似,是其轻量型信号量简化实现版。用于在ISR中发送任务通知。
vTaskNotifyGiveFromISR对于通知值的处理是累加(该接口默认了对通知值的处理是eIncrement,专用于信号量)。
代码分析见xTaskGenericNotifyFromISR,不再赘述。
3.2.6 ulTaskNotifyTake
#if( configUSE_TASK_NOTIFICATIONS == 1 )
uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait )
{
uint32_t ulReturn;
taskENTER_CRITICAL();
{
/* Only block if the notification count is not already non-zero. */
if( pxCurrentTCB->ulNotifiedValue == 0UL )
{
/* Mark this task as waiting for a notification. */
pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION;
if( xTicksToWait > ( TickType_t ) 0 )
{
prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
traceTASK_NOTIFY_TAKE_BLOCK();
/* All ports are written to allow a yield in a critical
section (some will yield immediately, others wait until the
critical section exits) - but it is not something that
application code should ever do. */
portYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
taskEXIT_CRITICAL();
taskENTER_CRITICAL();
{
traceTASK_NOTIFY_TAKE();
ulReturn = pxCurrentTCB->ulNotifiedValue;
if( ulReturn != 0UL )
{
if( xClearCountOnExit != pdFALSE )
{
pxCurrentTCB->ulNotifiedValue = 0UL;
}
else
{
pxCurrentTCB->ulNotifiedValue = ulReturn - 1;
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
}
taskEXIT_CRITICAL();
return ulReturn;
}
#endif /* configUSE_TASK_NOTIFICATIONS */
ulTaskNotifyTake用于取出通知值,与xTaskNotifyGive或vTaskNotifyGiveFromISR搭配使用,专用于轻量型信号量;
代码分析:
- 进临界区,关闭中断;
- 判断通知值是否为0(信号量为0),如果是,则在切换为等待通知状态前需要做如下工作:
- 将通知状态设置为taskWAITING_NOTIFICATION,标识等待通知(等待信号量);
- 参数xTicksToWait>0,表示阻塞等待通知信号量,调用prvAddCurrentTaskToDelayedList将任务加入delay list,并主动让步,任务进入阻塞态;
- 出临界区,开中断;
- 进临界区,关闭中断(到这里,要么任务收到通知被唤醒,要么阻塞时间超时唤醒,要么是非阻塞的接口调用);
- 标记ulReturn为通知值;
- 如果通知值不为0,说明已经收到通知(其他任务或ISR释放了信号量)。根据参数xClearCountOnExit执行:
- 如果xClearCountOnExit为pdTRUE,则将通知值清0;
- 否则,将通知值减一;
- 设置通知状态为taskNOT_WAITING_NOTIFICATION;
- 出临界区,开中断;
- 返回ulReturn(通知值/信号量);
4. 总结
专业版接口:
对于xTaskNotify/xTaskNotifyFromISR,根据参数eAction,任务通知即为轻量型的事件组、信号量、队列(深度为1)、邮箱。
eAction | 说明 |
---|---|
eSetBits | 用于设置对应比特位,设置值为ulValue,基于此实现轻量级事件组 |
eIncrement | 累加通知值,基于此实现轻量级信号量 |
eSetValueWithOverwrite | 覆盖通知值,将其设置为ulValue。基于此实现轻量级邮箱 |
eSetValueWithoutOverwrite | 仅在通知值被读取后才设置,设置值为ulValue,否则不修改通知值,标记返回失败,基于此实现轻量级的长度为1的队列 |
eNoAction | 什么都不做 |
简化版接口:
对于xTaskNotifyGive/vTaskNotifyGiveFromISR/ulTaskNotifyTake,其是轻量级的信号量实现。
参考链接
本文来自博客园,作者:流翎,转载请注明原文链接:https://www.cnblogs.com/hjx168/p/17945280