FreeRTOS 任务通知

news2024/7/2 2:55:25

文章目录

  • 一、任务通知简介
  • 二、发送任务通知
    • 1. 函数 xTaskNotify()
    • 2. 函数 xTaskNotifyFromISR()
    • 3. 函数 xTaskNotifyGive()
    • 4. 函数 vTaskNotifyGiveFromISR()
    • 5. 函数 xTaskNotifyAndQuery()
    • 6. 函数 xTaskNotifyAndQueryFromISR()
  • 三、任务通知通用发送函数
    • 1. 任务级任务通知通用发送函数
    • 2. 中断级任务通知发送函数
  • 四、获取任务通知
    • 1. 函数 ulTaskNotifyTake()
    • 2. 函数 xTaskNotifyWait()


一、任务通知简介

任务通知在 FreeRTOS 中是一个可选的功能,要使用任务通知的话就需要将宏
configUSE_TASK_NOTIFICATIONS 定义为 1。

FreeRTOS 的每个任务都有一个 32 位的通知值,任务控制块中的成员变量 ulNotifiedValue就是这个通知值。任务通知是一个事件,假如某个任务通知的接收任务因为等待任务通知而阻塞的话,向这个接收任务发送任务通知以后就会解除这个任务的阻塞状态。也可以更新接收任务的任务通知值,任务通知可以通过如下方法更新接收任务的通知值:
● 不覆盖接收任务的通知值(如果上次发送给接收任务的通知还没被处理)。
● 覆盖接收任务的通知值。
● 更新接收任务通知值的一个或多个 bit。
● 增加接收任务的通知值。

合理、灵活的使用上面这些更改任务通知值的方法可以在一些场合中替代队列、二值信号量、计数型信号量和事件标志组。使用任务通知来实现二值信号量功能的时候,解除任务阻塞的时间比直接使用二值信号量要快 45%(FreeRTOS 官方测试结果,使用 v8.1.2 版本中的二值信号量,GCC 编译器,-O2 优化的条件下测试的,没有使能断言函数 configASSERT()),并且使用的 RAM 更少!

任务通知的发送使用函数 xTaskNotify()或者 xTaskNotifyGive()(还有此函数的中断版本)来完 成 , 这 个 通 知 值 会 一 直 被 保 存 着 , 直 到 接 收 任 务 调 用 函 数 xTaskNotifyWait() 或 者ulTaskNotifyTake()来获取这个通知值。假如接收任务因为等待任务通知而阻塞的话那么在接收到任务通知以后就会解除阻塞态。

任务通知虽然可以提高速度,并且减少 RAM 的使用,但是任务通知也是有使用限制的:
● FreeRTOS 的任务通知只能有一个接收任务,其实大多数的应用都是这种情况。
● 接收任务可以因为接收任务通知而进入阻塞态,但是发送任务不会因为任务通知发送
失败而阻塞。

二、发送任务通知

任务通知发送函数有 6 个,如下表所示:
在这里插入图片描述

1. 函数 xTaskNotify()

此函数用于发送任务通知,此函数发送任务通知的时候带有通知值,此函数是个宏,真正执行的函数 xTaskGenericNotify(),函数原型如下:

BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify, 
						uint32_t ulValue, 
						eNotifyAction eAction )

参数:
xTaskToNotify: 任务句柄,指定任务通知是发送给哪个任务的。
ulValue: 任务通知值。
eAction: 任务通知更新的方法,eNotifyAction 是个枚举类型,在文件 task.h 中有如下定义:

typedef enum
{
	eNoAction = 0,
	eSetBits, //更新指定的 bit
	eIncrement, //通知值加一
	eSetValueWithOverwrite, //覆写的方式更新通知值
	eSetValueWithoutOverwrite //不覆写通知值
} eNotifyAction;

此参数可以选择枚举类型中的任意一个,不同的应用环境其选择也不同。

返回值:
pdFAIL: 当参数 eAction 设置为 eSetValueWithoutOverwrite 的时候,如果任务通知值没有更新成功就返回 pdFAIL。
pdPASS: eAction 设置为其他选项的时候统一返回 pdPASS。

2. 函数 xTaskNotifyFromISR()

此函数用于发送任务通知,是函数 xTaskNotify()的中断版本,此函数是个宏,真正执行的是函数 xTaskGenericNotifyFromISR(),此函数原型如下:

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

参数:
xTaskToNotify: 任务句柄,指定任务通知是发送给哪个任务的。
ulValue: 任务通知值。
eAction: 任务通知更新的方法。
pxHigherPriorityTaskWoken: 记退出此函数以后是否进行任务切换,这个变量的值函数会自动设置的,用户不用进行设置,用户只需要提供一个变量来保存这个值就行了。当此值为 pdTRUE 的时候在退出中断服务函数之前一定要进行一次任务切换。

返回值:
pdFAIL: 当参数 eAction 设置为 eSetValueWithoutOverwrite 的时候,如果任务通知值没有更新成功就返回 pdFAIL。
pdPASS: eAction 设置为其他选项的时候统一返回 pdPASS。

3. 函数 xTaskNotifyGive()

发送任务通知,相对于函数 xTaskNotify(),此函数发送任务通知的时候不带有通知值。此函数只是将任务通知值简单的加一,此函数是个宏,真正执行的是函数 xTaskGenericNotify(),
此函数原型如下:

BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify );

参数:
xTaskToNotify: 任务句柄,指定任务通知是发送给哪个任务的。

返回值:
pdPASS: 此函数只会返回 pdPASS。

4. 函数 vTaskNotifyGiveFromISR()

此函数为 xTaskNotifyGive()的中断版本,用在中断服务函数中,函数原型如下:

void vTaskNotifyGiveFromISR( TaskHandle_t xTaskHandle, 
							 BaseType_t * pxHigherPriorityTaskWoken );

参数:
xTaskToNotify: 任务句柄,指定任务通知是发送给哪个任务的。
pxHigherPriorityTaskWoken: 记退出此函数以后是否进行任务切换,这个变量的值函数会自动设置的,用户不用进行设置,用户只需要提供一个变量来保存这个值就行了。当此值为 pdTRUE 的时候在退出中断服务函数之前一定要进行一次任务切换。

返回值:
无。

5. 函数 xTaskNotifyAndQuery()

此函数和 xTaskNotify()很类似,此函数比 xTaskNotify()多一个参数,此参数用来保存更新前的通知值。此函数是个宏,真正执行的是函数 xTaskGenericNotify(),此函数原型如下:

BaseType_t xTaskNotifyAndQuery ( TaskHandle_t xTaskToNotify, 
							 	 uint32_t ulValue, 
								 eNotifyAction eAction 
								 uint32_t * pulPreviousNotificationValue);

参数:
xTaskToNotify: 任务句柄,指定任务通知是发送给哪个任务的。
ulValue: 任务通知值。
eAction: 任务通知更新的方法。
pulPreviousNotificationValue: 用来保存更新前的任务通知值。

返回值:
pdFAIL: 当参数 eAction 设置为 eSetValueWithoutOverwrite 的时候,如果任务通知值没有更新成功就返回 pdFAIL。
pdPASS: eAction 设置为其他选项的时候统一返回 pdPASS。

6. 函数 xTaskNotifyAndQueryFromISR()

此函数为 xTaskNorityAndQuery()的中断版本,用在中断服务函数中。此函数同样为宏,真正执行的是函数 xTaskGenericNotifyFromISR(),此函数的原型如下:

BaseType_t xTaskNotifyAndQueryFromISR ( TaskHandle_t xTaskToNotify, 
										uint32_t ulValue, 
										eNotifyAction eAction, 
										uint32_t * pulPreviousNotificationValue
										BaseType_t * pxHigherPriorityTaskWoken );

参数:
xTaskToNotify: 任务句柄,指定任务通知是发送给哪个任务的。
ulValue: 任务通知值。
eAction: 任务通知更新的方法。
pulPreviousNotificationValue: 用来保存更新前的任务通知值。
pxHigherPriorityTaskWoken: 记退出此函数以后是否进行任务切换,这个变量的值函数会自动设置的,用户不用进行设置,用户只需要提供一个变量来保存这个值就行了。当此值为 pdTRUE 的时候在退出中断服务函数之前一定要进行一次任务切换。

返回值:
pdFAIL: 当参数 eAction 设置为 eSetValueWithoutOverwrite 的时候,如果任务通知值没有更新成功就返回 pdFAIL。
pdPASS: eAction 设置为其他选项的时候统一返回 pdPASS。

三、任务通知通用发送函数

1. 任务级任务通知通用发送函数

在前面学习了 3 个任务级任务通知发送函数:xTaskNotify()、xTaskNotifyGive()
和 xTaskNotifyAndQuery(),这三个函数最终调用的都是函数 xTaskGenericNotify()!此函数在文件 tasks.c 中有如下定义,缩减后的函数如下:

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 ) (1)
		{
			*pulPreviousNotificationValue = pxTCB->ulNotifiedValue; (2)
		}
		ucOriginalNotifyState = pxTCB->ucNotifyState; (3)
		pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED; (4)
		switch( eAction )
		{
			case eSetBits : (5)
			pxTCB->ulNotifiedValue |= ulValue;
			break;
			case eIncrement : (6)
				( pxTCB->ulNotifiedValue )++;
				break;
			case eSetValueWithOverwrite: (7)
				pxTCB->ulNotifiedValue = ulValue;
				break;
			case eSetValueWithoutOverwrite : (8)
				if( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED )
				{
					pxTCB->ulNotifiedValue = ulValue;
				}
				else
				{
					xReturn = pdFAIL;
				}
				break;
			case eNoAction:
				break;
		}
		traceTASK_NOTIFY();
		//如果任务因为等待任务通知而进入阻塞态的话就需要解除阻塞
		if( ucOriginalNotifyState == taskWAITING_NOTIFICATION ) (9)
		{
			( void ) uxListRemove( &( pxTCB->xStateListItem ) ); (10)
			prvAddTaskToReadyList( pxTCB ); (11)
			/******************************************************************/
			/********************省略相关的条件编译代码************************/
			/******************************************************************/
			if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) (12)
			{
				//解除阻塞的任务优先级比当前运行的任务优先级高,所以需要进行
				//任务切换。
				taskYIELD_IF_USING_PREEMPTION();
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}
	taskEXIT_CRITICAL();
	return xReturn; (13)
}

(1)、判断参数 pulPreviousNotificationValue 是否有效,因为此参数用来保存更新前的任务通知值。

(2)、如果参数 pulPreviousNotificationValue 有效的话就用此参数保存更新前的任务通知值。

(3)、保存任务通知状态,因为下面会修改这个状态,后面我们要根据这个状态来确定是否将任务从阻塞态解除。

(4)、更新任务通知状态为 taskNOTIFICATION_RECEIVED。

(5)、根据不同的更新方式做不同的处理,如果为 eSetBits 的话就将指定的 bit 置 1。也就是更新接收任务通知值的一个或多个 bit。

(6)、如果更新方式为 eIncrement 的话就将任务通知值加一。

(7)、如果更新方式为 eSetValueWithOverwrite 的话就直接覆写原来的任务通知值。

(8)、如果更新方式为 eSetValueWithoutOverwrite 的话就需要判断原来的任务通知值是否被处理,如果已经被处理了就更新为任务通知值。如果此前的任务通知值话没有被处理的话就标记 xReturn 为 pdFAIL,后面会返回这个值。

(9)、根据(3)中保存的接收任务之前的状态值来判断是否有任务需要解除阻塞,如果在任务通知值被更新前任务处于 taskWAITING_NOTIFICATION 状态的话就说明有任务因为等待任务通知值而进入了阻塞态。

(10)、将任务从状态列表中移除。

(11)、将任务重新添加到就绪列表中。

(12)、判断刚刚解除阻塞的任务优先级是否比当前正在运行的任务优先级高,如果是的话需要进行一次任务切换。

(13)、返回 xReturn 的值,pdFAIL 或 pdPASS。

2. 中断级任务通知发送函数

中 断 级 任 务 通 知 发 送 函 数 也 有 三 个 , 分 别 为 : xTaskNotifyFromISR() 、
xTaskNotifyAndQueryFromISR()和 vTaskNotifyGiveFromISR()。其中函数 xTaskNotifyFromISR()和 xTaskNotifyAndQueryFromISR()最终调用的都是函数 xTaskGenericNotifyFromISR(),此函数的原型如下:

BaseType_t xTaskGenericNotifyFromISR(   TaskHandle_t xTaskToNotify, 
										uint32_t ulValue, 
										eNotifyAction eAction, 
										uint32_t * pulPreviousNotificationValue, 
										BaseType_t * pxHigherPriorityTaskWoken )

参数:
xTaskToNotify: 任务句柄,指定任务通知是发送给哪个任务的。
ulValue: 任务通知值。
eAction: 任务通知更新的方法。
pulPreviousNotificationValue: 用来保存更新前的任务通知值。
pxHigherPriorityTaskWoken: 记退出此函数以后是否进行任务切换,这个变量的值函数会自动设置的,用户不用进行设置,用户只需要提供一个变量来保存这个值就行了。当此值为 pdTRUE 的时候在退出中断服务函数之前一定要进行一次任务切换。

返回值:
pdFAIL: 当参数 eAction 设置为 eSetValueWithoutOverwrite 的时候,如果任务通知值没有更新成功就返回 pdFAIL。
pdPASS: eAction 设置为其他选项的时候统一返回 pdPASS。

函数 xTaskGenericNotifyFromISR()在文件 tasks.c 中有定义,函数源码如下:

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 );
	portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
	pxTCB = ( TCB_t * ) xTaskToNotify;
	uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
	{
		if( pulPreviousNotificationValue != NULL ) (1)
		{
			*pulPreviousNotificationValue = pxTCB->ulNotifiedValue;
		}
		ucOriginalNotifyState = pxTCB->ucNotifyState; (2)
		pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED; (3)
		switch( eAction ) (4)
		{
			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
				{
					xReturn = pdFAIL;
				}
				break;
			case eNoAction :
				break;
		}
		traceTASK_NOTIFY_FROM_ISR();
		//如果任务因为等待任务通知而进入阻塞态的话就需要解除阻塞
		if( ucOriginalNotifyState == taskWAITING_NOTIFICATION ) (5)
		{
			configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) ==\
			NULL );
			if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) (6)
			{
				( void ) uxListRemove( &( pxTCB->xStateListItem ) );
				prvAddTaskToReadyList( pxTCB );
			}
			else (7)
			{
				vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
			}
			if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) (8)
			{
				//解除阻塞的任务优先级比当前运行任务的优先级高,所以需要标记
				//在退出中断服务函数的时候需要做任务切换。
				if( pxHigherPriorityTaskWoken != NULL )
				{
					*pxHigherPriorityTaskWoken = pdTRUE;
				}
				else
				{
					xYieldPending = pdTRUE;
				}
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
	}
	portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
	return xReturn;
}

(1)、判断参数 pulPreviousNotificationValue 是否有效,因为此参数用来保存更新前的任务通知值。如果参数 pulPreviousNotificationValue 有效的话就用此参数保存更新前的任务通知值。

(2)、保存任务通知状态,因为下面会修改这个状态,后面我们要根据这个状态来确定是否将任务解除阻塞态。

(3)、更新任务通知状态 taskNOTIFICATION_RECEIVED。

(4)、根据不同的通知值更新方式来做不同的处理,与函数 xTaskGenericNotify()的处理过程一样。

(5)、根据(2)中保存的接收任务之前的状态值来判断是否有任务需要解除阻塞,如果在任务通知值被更新前任务处于 taskWAITING_NOTIFICATION 状态的话就说明有任务因为等待任务通知值而进入了阻塞态。

(6)、判断任务调度器是否上锁,如果调度器没有上锁的话就将任务从状态列表中移除,然后重新将任务添加到就绪列表中。

(7)、如果任务调度器上锁了的话就将任务添加到列表 xPendingReadyList 中。

(8)、判断任务解除阻塞的任务优先级是否比当前任务优先级高,如果是的话就将
pxHigherPriorityTaskWoken 标记 pdTRUE。如果参数 pxHigherPriorityTaskWoken 无效的话就将全局变量 xYieldPending 标记为 pdTRUE。

还有另外一个用于中断服务函数的任务通知发送函数 vTaskNotifyGiveFromISR(),此函数和 xTaskGenericNotifyFromISR()极其类似。此函数用于将任务通知值加一,大家可以自行分析一下此函数。

四、获取任务通知

获取任务通知的函数有两个,如下表所示:
在这里插入图片描述

1. 函数 ulTaskNotifyTake()

此函数为获取任务通知函数,当任务通知用作二值信号量或者计数型信号量的时候可以使用此函数来获取信号量,函数原型如下:

uint32_t ulTaskNotifyTake(  BaseType_t xClearCountOnExit, 
							TickType_t xTicksToWait );

参数:
xClearCountOnExit: 参数为 pdFALSE 的话在退出函数 ulTaskNotifyTake()的时候任务通知值减一,类似计数型信号量。当此参数为 pdTRUE 的话在退出函数的时候任务任务通知值清零,类似二值信号量。
xTickToWait: 阻塞时间。

返回值:
任何值 : 任务通知值减少或者清零之前的值。
此函数在文件 tasks.c 中有定义,代码如下:

uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait )
{
	uint32_t ulReturn;
	taskENTER_CRITICAL();
	{
		if( pxCurrentTCB->ulNotifiedValue == 0UL ) (1)
		{
			pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION; (2)
			if( xTicksToWait > ( TickType_t ) 0 ) (3)
			{
				prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
				traceTASK_NOTIFY_TAKE_BLOCK();
				portYIELD_WITHIN_API();
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}
	taskEXIT_CRITICAL();
	taskENTER_CRITICAL();
	{
		traceTASK_NOTIFY_TAKE();
		ulReturn = pxCurrentTCB->ulNotifiedValue; (4)
		if( ulReturn != 0UL ) (5)
		{
			if( xClearCountOnExit != pdFALSE ) (6)
			{
				pxCurrentTCB->ulNotifiedValue = 0UL;
			}
			else
			{
				pxCurrentTCB->ulNotifiedValue = ulReturn - 1; (7)
			}
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
		pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION; (8)
	}
	taskEXIT_CRITICAL();
	return ulReturn;
}

(1)、判断任务通知值是否为 0,如果为 0 的话说明还没有接收到任务通知。

(2)、修改任务通知状态为 taskWAITING_NOTIFICATION。

(3)、如果阻塞时间不为 0 的话就将任务添加到延时列表中,并且进行一次任务调度。

(4)、如果任务通知值不为 0 的话就先获取任务通知值。

(5)、任务通知值大于 0。

(6)、参数 xClearCountOnExit 不为 pdFALSE,那就将任务通知值清零。

(7)、如果参数 xClearCountOnExit 为 pdFALSE 的话那就将任务通知值减一。

(8)、更新任务通知状态为 taskNOT_WAITING_NOTIFICATION。

2. 函数 xTaskNotifyWait()

此函数也是用来获取任务通知的,不过此函数比 ulTaskNotifyTake()更为强大,不管任务通知用作二值信号量、计数型信号量、队列和事件标志组中的哪一种,都可以使用此函数来获取任务通知。但是当任务通知用作位置信号量和计数型信号量的时候推荐使用函数ulTaskNotifyTake()。此函数原型如下:

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

参数:
ulBitsToClearOnEntry: 当没有接收到任务通知的时候将任务通知值与此参数的取反值进行按位与运算,当此参数为 0xffffffff 或者 ULONG_MAX 的时候就会将任务
通知值清零。
ulBitsToClearOnExit: 如果接收到了任务通知,在做完相应的处理退出函数之前将任务通知值与此参数的取反值进行按位与运算,当此参数为 0xffffffff 或者ULONG_MAX 的时候就会将任务通知值清零。
pulNotificationValue: 此参数用来保存任务通知值。
xTickToWait: 阻塞时间。

返回值:
pdTRUE: 获取到了任务通知。
pdFALSE: 任务通知获取失败。
此函数在文件 tasks.c 中有定义,代码如下:

BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, 
							uint32_t ulBitsToClearOnExit, 
							uint32_t * pulNotificationValue, 
							TickType_t xTicksToWait )
{
	BaseType_t xReturn;
	taskENTER_CRITICAL();
	{
		if( pxCurrentTCB->ucNotifyState != taskNOTIFICATION_RECEIVED ) (1)
		{
			pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnEntry; (2)
			pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION; (3)
			if( xTicksToWait > ( TickType_t ) 0 ) (4)
			{
				prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
				traceTASK_NOTIFY_WAIT_BLOCK();
				portYIELD_WITHIN_API();
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}
	taskEXIT_CRITICAL();
	taskENTER_CRITICAL();
	{
		traceTASK_NOTIFY_WAIT();
		if( pulNotificationValue != NULL ) (5)
		{
			*pulNotificationValue = pxCurrentTCB->ulNotifiedValue;
		}
		if( pxCurrentTCB->ucNotifyState == taskWAITING_NOTIFICATION ) (6)
		{
			xReturn = pdFALSE;
		}
		else
		{
			pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnExit; (7)
			xReturn = pdTRUE;
		}
		pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION; (8)
	}
	taskEXIT_CRITICAL();
	return xReturn;
}

(1)、任务同通状态不为 taskNOTIFICATION_RECEIVED。

(2)、将任务通知值与参数 ulBitsToClearOnEntry 的取反值进行按位与运算。

(3)、任务通知状态改为 taskWAITING_NOTIFICATION。

(4)、如果阻塞时间大于 0 的话就要将任务添加到延时列表中,并且进行一次任务切换。

(5)、如果任务通知状态为 taskNOTIFICATION_RECEIVED,并且参数pulNotificationValue有效的话就保存任务通知值。

(6)、如果任务通知的状态又变为 taskWAITING_NOTIFICATION 的话就标记 xRetur 为
pdFALSE。

(7)、如果任务通知的状态一直为 taskNOTIFICATION_RECEIVED 的话就将任务通知的值与参数 ulBitsToClearOnExit 的取反值进行按位与运算,并且标记 xReturn 为pdTRUE,表示获取任务通知成功。

(8)、标记任务通知的状态为 taskNOT_WAITING_NOTIFICATION。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/482238.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一、环境搭建

一、创建新的环境空间 conda create -n yanyu python3.7.4 yanyu为新的环境空间名称,可自定义修改 conda activate yanyu 切换一下环境空间 二、安装sklearn并验证 安装相关包 pip install numpy pip install scipy pip install matplotlib pip install sklear…

Python小姿势 - Python面向对象

Python面向对象 Python是一种面向对象的编程语言,它能够把很复杂的事情简单化。面向对象最大的特点就是数据和对数据的操作分离开了。 举个例子,假设你要做一个学生成绩管理系统,在这个系统里,你需要存储每个学生的姓名、年龄、成…

【2023 年第十三届 MathorCup 高校数学建模挑战赛】A 题 量子计算机在信用评分卡组合优化中的应用 42页论文及代码

【2023 年第十三届 MathorCup 高校数学建模挑战赛】A 题 量子计算机在信用评分卡组合优化中的应用 42页论文及代码 相关信息 【2023 年第十三届 MathorCup 高校数学建模挑战赛】A 题 量子计算机在信用评分卡组合优化中的应用 详细建模过程解析及代码实现 1 题目 在银行信用…

【python知识】推导式和生成器

一、说明 Python 推导式,是针对容器对象(列表,字典,集合,元组)的产生方式的语句。它可以从一个数据序列构建另一个新的数据序列的结构体。 Python 支持各种数据结构的推导式: 列表(list)推导式字典(dict)推…

从零开始实现 std::string:让你更深入地了解字符串的本质

文章目录 前言string类 的模拟实现一&#xff0c;搭建框架二&#xff0c;重载输入输出操作符 ‘<<’ ‘>>’1. 重载操作符 ‘<<’2.重载操作符 ‘>>’且看方式一来看方式二 三&#xff0c;实现构造函数方式一方式二 四&#xff0c;实现拷贝构造和重载赋…

TCP之报文格式解析

TCP网络协议是较常用的&#xff0c;也基本上都会接触&#xff0c;那么来简单了解下它吧。TCP 是一种面向连接的、可靠的传输协议&#xff0c;它能够将数据分成一些小块&#xff0c;并通过 Internet 进行传输。在 TCP 中&#xff0c;数据被分割成一些称为 TCP 报文段&#xff08…

JetBrains 公布 WebStorm 2023.2 路线图

JetBrains 已公布了 WebStorm 2023.2 版本的路线图&#xff0c;以便用户可以率先了解到官方的规划以及能够预览一下未来能够用上的新功能。 主要聚焦于以下内容&#xff1a; 稳定的新 UI。这是此版本中的优先事项之一。CSS 嵌套支持。WebStorm 2023.2 计划将添加对 CSS 嵌套功能…

TensorRT:自定义插件学习与实践 002:实现GELU

代码连接:https://github.com/codesteller/trt-custom-plugin TensorRT版本的选择 教程代码对应的版本TensorRT-6.0.1.8,我尝试使用TensorRT-7.2.3.4也能通过编译 set_ifndef(TRT_LIB /usr/local/TensorRT-7.2.3.4/lib) set_ifndef(TRT_INCLUDE /usr/local/TensorRT-7.2.3.4…

是不是在为 API 烦恼 ?好用免费的api接口大全呼之欲出

前期回顾 “ ES6 —— 让你的JavaScript代码从平凡到精彩 “_0.活在风浪里的博客-CSDN博客Es6 特性https://blog.csdn.net/m0_57904695/article/details/130408701?spm1001.2014.3001.5501 &#x1f44d; 本文专栏&#xff1a;开发技巧 先说本文目的&#xff0c;本文会分…

有效日志管理在软件开发和运营中的作用

作者&#xff1a;Luca Wintergerst, David Hope, Bahubali Shetti 当今存在的快速软件开发过程需要扩展和复杂的基础架构和应用程序组件&#xff0c;并且操作和开发团队的工作不断增长且涉及多个方面。 有助于管理和分析遥测数据的可观察性是确保应用程序和基础架构的性能和可靠…

JavaScript实现输入数值,判断是否为(任意)三角形的代码

以下为实现输入数值&#xff0c;判断是否为&#xff08;任意&#xff09;三角形的代码和运行截图 目录 前言 一、实现输入数值&#xff0c;判断是否为三角形 1.1 运行流程及思想 1.2 代码段 1.3 JavaScript语句代码 1.4 运行截图 二、实现输入数值&#xff0c;判断是否为…

PLC模糊控制模糊PID(梯形图实现+算法分析)

博途PLC的模糊PID控制详细内容请查看下面的博客文章: Matlab仿真+博途PLC模糊PID控制完整SCL源代码参考(带模糊和普通PID切换功能)_博途怎么实现模糊pid_RXXW_Dor的博客-CSDN博客模糊PID的其它相关数学基础,理论知识大家可以参看专栏的其它文章,这里不再赘述,本文就双容…

01背包问题个人剖析

背包问题 文章目录 背包问题1 01背包问题1.1 问题阐述1.2 问题分析 背包问题中我最初的一些疑惑 1 01背包问题 我参考了文献背包九讲。https://github.com/tianyicui/pack/raw/master/V2.pdf 背包九讲的作者是ACM大牛崔天翼。 1.1 问题阐述 有 N N N件物品和一个容量为 V V …

Java程序猿搬砖笔记(十二)

文章目录 PostConstruct注解Mybatis的mapper-locations配置JsonFormat实现原理IDEA String Manipulation插件使用及设置快捷键在Windows中测试服务器端口是否开放Centos开放端口Nginx常用配置详解Nginx里面的路径定位关键词root、aliaszuul里面的prefix 和 strip-prefix学习解决…

【三十天精通Vue 3】第二十四天 Vue3 移动端适配和响应式布局

✅创作者&#xff1a;陈书予 &#x1f389;个人主页&#xff1a;陈书予的个人主页 &#x1f341;陈书予的个人社区&#xff0c;欢迎你的加入: 陈书予的社区 &#x1f31f;专栏地址: 三十天精通 Vue 3 文章目录 引言一、 移动端适配概述1.1 为什么需要移动端适配&#xff1f;1.…

3.5 并行存储器

学习步骤&#xff1a; 如果我要学习并行存储器&#xff0c;我会采取以下几个步骤&#xff1a; 了解并行存储器的基本概念和原理。学习并行存储器的前提是要对存储器的基本原理有所了解&#xff0c;包括存储器的分类、工作原理、读写时序等。 学习并行存储器的特点和应用。并行…

Java每日一练(20230502)

目录 1. 二叉搜索树的最近公共祖先 &#x1f31f;&#x1f31f; 2. 随机分组问题 &#x1f31f; 3. K 个一组翻转链表 &#x1f31f;&#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练…

Vue 框架入门介绍

前言 前端时间工作任务没有那么忙&#xff0c;在技术总监沟通中他认为我自己花点时间做技术扩展&#xff0c;由于项目中用到前端部分功能&#xff0c;框架用的是Vue&#xff0c;本身项目中和前端同时接触比较多&#xff0c;而且公司有现成的项目可以供我去练习&#xff0c;所以…

存储资源调优技术——SmartMigration智能数据迁移技术

目录 基本概念 工作原理 注意事项 基本概念 智能数据迁移技术是业务迁移的关键技术 在不中断主机业务的情况下&#xff0c;实现源LUN上的业务完整--业务相关的所有数据 迁移到目标LUN上 工作原理 业务数据同步 创建SmartMigration&#xff0c;源LUN和目标LUN之间建立Pair关系&a…

RabbitMq、Kafka、RocketMq整理

MQ的主要作用:异步提高性能、解耦提高扩展性、削峰。 一、常见中间件对比 Kafka、RocketMq和RabbitMq最大的区别就是:前两个是分布式存储。 1.1、ActiveMq 优点:1)完全支持jms规范的消息中间件 ,2)提供丰富的api, 3)多种集群构建模式。 缺点:)在高并发的场景下,性能可…