验证xTaskResumeAll是否能够唤醒已被vTaskSuspend的任务
先说结论,xTaskResumeAll 无法唤醒已被vTaskSuspend的任务。
其实从xTaskResumeAll 的源码及vTaskResume的源码就可以看出来,两个函数的功能相似确截然不同;
xTaskResumeAll 主要是释放计数器,以及将等待的任务转移到就绪列表,并不涉及到挂起的任务
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;
}
vTaskResume 任务很明显对挂起列表的任务做了处理
void vTaskResume( TaskHandle_t xTaskToResume )
{
/*把句柄赋值给任务控制块指针*/
TCB_t * const pxTCB = ( TCB_t * ) xTaskToResume;
/* It does not make sense to resume the calling task. */
configASSERT( xTaskToResume );
/* The parameter cannot be NULL as it is impossible to resume the
currently executing task. */
/*带进来的任务块不能是正在运行任务,不能等于NULL,*/
if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) )
{
/*进入临界区*/
taskENTER_CRITICAL();
{ /*判断这个任务是在挂起列表中*/
if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE )
{
traceTASK_RESUME( pxTCB );
/* As we are in a critical section we can access the ready
lists even if the scheduler is suspended. */
/*移除状态列表,不管在什么列表都会被移除,这里将原本挂起的任务添加到就绪列表中*/
( void ) uxListRemove( &( pxTCB->xStateListItem ) );
/*添加到就绪列表中*/
prvAddTaskToReadyList( pxTCB );
/* We may have just resumed a higher priority task. */
/*优先级高于当前运行任务优先级*/
if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
{
/* This yield may not cause the task just resumed to run,
but will leave the lists in the correct state for the
next yield. */
/*任务切换*/
taskYIELD_IF_USING_PREEMPTION();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
/*退出临界区*/
taskEXIT_CRITICAL();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
看完了两个函数的源码,我们对两个函数的区别有了一定了解。下面实际测试一下。
可以分为以下步骤:
1 创建一个任务,并挂起它
2 在其他任务中调用xTaskResumeAll
3 查询挂起的任务状态。
1 创建一个任务,并挂起它
xTaskCreate(motion_alg_repeat_task, "motion_alg_repeat", 4096, 0, 2, &motion_alg_repeat);//
vTaskSuspend(motion_alg_repeat);
2 、3
//测试xTaskResumeAll是否能够唤醒被suspend的任务
// cur == eSuspend;说明xTaskResumeAll不能唤醒被vTaskSuspend的任务
vTaskSuspendAll();
xTaskResumeAll();
extern TaskHandle_t motion_alg_repeat;
eTaskState cur = eTaskGetState(motion_alg_repeat);
调试运行,发现cur == eSuspend;说明当前任务被挂起。
xTaskResumeAll不能唤醒被vTaskSuspend的任务