FreeRTOS: vTaskSuspendAll xTaskResumeAll详解

FreeRTOS: vTaskSuspendAll xTaskResumeAll详解

当需要处理某些全局变量(数据)的时候,为了防止被同时多个线程修改引起问题,需要把线程抢占功能暂时屏蔽,需要用到vTaskSuspendAll()xTaskResumeAll()

void vTaskSuspendAll( void ):设置关闭线程调度的标志位

代码详解:

void vTaskSuspendAll( void )
{
	//系统维护一个计数uxSchedulerSuspended,当它大于0时候表示禁止调度,等于0则打开调度(允许调度
	++uxSchedulerSuspended;
}

void xTaskResumeAll( void ):恢复线程调度,且处理期间的数据

代码详解:
1,如果关闭调度的时候,有等候的线程(pending )需要把线程转移到就绪列表中prvAddTaskToReadyList.
2,如果关闭调度的时候,经过的多个Tick,需要执行对应的次数的xTaskIncrementTick.
3,如果以上都没有发生,继续执行原有的线程.

BaseType_t xTaskResumeAll( void )
{
TCB_t *pxTCB = NULL;
BaseType_t xAlreadyYielded = pdFALSE;

	//屏蔽中断.
	taskENTER_CRITICAL();
	{
		// 将计数减一
		--uxSchedulerSuspended;
		// 如果等于0,则允许调度
		if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
		{
			//线程数量大于0,才可能进行调度
			if( uxCurrentNumberOfTasks > ( UBaseType_t ) 0U )
			{
				/* pending 中的线程数量(停止线程调度时候,积攒下来的线程数) > 0		 */
				while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE )
				{
					/*将所有在xPendingReadyList中的任务移到对应的就绪链表中 */
					pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) );
					( void ) uxListRemove( &( pxTCB->xEventListItem ) );
					( void ) uxListRemove( &( pxTCB->xStateListItem ) );
					prvAddTaskToReadyList( pxTCB );

					/* 如果pending中的线程任务优先级大于当前线程的优先级.需要做调度线程 */
					if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
					{
						xYieldPending = pdTRUE;
					}
				}

				if( pxTCB != NULL )
				{
					/* 获取下次需要唤醒线程的那一刻的时间.如果没有那就 portMAX_DELAY
					如果有的话,把时间保存在xNextTaskUnblockTime中*/
					prvResetNextTaskUnblockTime();
				}

				/* 如果在禁止调度期间,有时钟节拍中断发生,则我们把发生的次数记录在uxPendedTicks中,称为丢失的时钟节拍数;
				我们在这里模拟uxMissedTicks次时钟节拍中断,也就是说调用uxPendedTicks次时钟节拍isr: vTaskIncrementTick()。
				这样保证了所有任务的延时量不会出现偏差,它们将在正确的时间被唤醒*/ */
				{
					UBaseType_t uxPendedCounts = uxPendedTicks; /* Non-volatile copy. */

					if( uxPendedCounts > ( UBaseType_t ) 0U )
					{
						do
						{
							/*xTaskIncrementTick:详细的可看下面
							1,重新增加xTickCount.
							2,线程中是否存在等待调度的信息.
							*/
							if( xTaskIncrementTick() != pdFALSE )
							{
								//存在需要调度的线程
								xYieldPending = pdTRUE;
							}
							--uxPendedCounts;
						} while( uxPendedCounts > ( UBaseType_t ) 0U );

						uxPendedTicks = 0;
					}
				}
 				//如果存在需要调度的线程
				if( xYieldPending != pdFALSE )
				{
					#if( configUSE_PREEMPTION != 0 )
					{
						xAlreadyYielded = pdTRUE;
					}
					#endif
					taskYIELD_IF_USING_PREEMPTION();
				}
			}
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}
	//放开中断
	taskEXIT_CRITICAL();

	return xAlreadyYielded;
}

代码分析:
1,累加Tick数.
2,是否在等待线程中转移到就绪列表的时候,有高优先级的任务.如果有返回TRUE.
3,xYieldPending ==TRUE => 返回TRUE.

BaseType_t xTaskIncrementTick( void )
{
TCB_t * pxTCB;
TickType_t xItemValue;
BaseType_t xSwitchRequired = pdFALSE;

	//是否进制调度
	if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
	{
		/* 保存累加后的,数据 */
		const TickType_t xConstTickCount = xTickCount + ( TickType_t ) 1;

		/* 如果累加后出现越界,需要对应相关信息 */
		xTickCount = xConstTickCount;
		if( xConstTickCount == ( TickType_t ) 0U )
		{
			/* 越界后的信息调整.
			1,记录越界次数xNumOfOverflows
			2,交换越界信息  pxDelayedTaskList <->pxOverflowDelayedTaskList
			*/
			taskSWITCH_DELAYED_LISTS();
		}
		

		/* 当前TIck大于等于,需要唤醒的线程时间 */
		if( xConstTickCount >= xNextTaskUnblockTime )
		{
			for( ;; )
			{
				if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )
				{
					/* 如果没有Delayed线程,不需要唤醒*/
					xNextTaskUnblockTime = portMAX_DELAY;
					break;
				}
				else
				{
					/* 从 pxDelayedTaskList 中获取,需要环形的线程 */
					pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );
					xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xStateListItem ) );
					
					if( xConstTickCount < xItemValue )
					{
						/*如果 pxDelayedTaskList 中的第一个线程需要唤醒的时间大于当前时间,代表着还需要继续睡眠 
						且下一个唤醒的时间是线程的时间 且退出.
						(因为pxDelayedTaskList 中的线程是根据唤醒的时间排序的)
						 */
						xNextTaskUnblockTime = xItemValue;
						break;
					}

					/* 把休眠中的线程 从等候pxDelayedTaskList 列表中删除*/
					( void ) uxListRemove( &( pxTCB->xStateListItem ) );

					/* 如果这个线程还有事件等待状态的话需要从,事件等待中删除. */
					if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
					{
						( void ) uxListRemove( &( pxTCB->xEventListItem ) );
					}
					

					/* 把线程转移到 就绪列表中 */
					prvAddTaskToReadyList( pxTCB );

					#if (  configUSE_PREEMPTION == 1 )
					{
						/* 如果唤醒的线程优先级高于当前线程需要调度一下. */
						if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
						{
							xSwitchRequired = pdTRUE;
						}
					}
					#endif /* configUSE_PREEMPTION */
				}
			}
		}

	}
	else
	{
		//如果是不可调度状态的话,需要把等待的TIck事件保存起来.等到恢复调度的时候,再处理.
		++uxPendedTicks;
	}

	#if ( configUSE_PREEMPTION == 1 )
	{
		//如果需要调度返回TRUE.
		if( xYieldPending != pdFALSE )
		{
			xSwitchRequired = pdTRUE;
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}
	#endif /* configUSE_PREEMPTION */

	return xSwitchRequired;
}
  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值