freertos- 任务基本概念与任务挂起和恢复解析(笔记)

1,任务状态

2,任务的优先级

  • 优先级数字越低表示任务的优先级越低,0的优先级最低,故configMAX_PRIORITIES-1的优先级最高。空闲任务的优先级最低,为0。
  • FreeRTOS调度器确保处于就绪态或运行态的高优先级的任务获取处理器使用权,换句话说就是处于就绪态的最高优先级的任务才会运行。
  • 当宏configUSE_TIME_SLICING定义为1的时候多个任务可以共用一个优先级,数量不限。
  • 默认情况下宏configUSE_TIME_SLICING已经定义为1.此时处于就绪态的优先级相同的任务就会使用时间片轮转调度器获取运行时间。
     

3,任务挂起和恢复的情形

 

如图4所示,任务挂起实现

void vTaskSuspend( TaskHandle_t xTaskToSuspend )
{
TCB_t *pxTCB;

	taskENTER_CRITICAL();
	{
		/* 如果在这里传递null,那么正在运行的任务将被挂起。. */
		pxTCB = prvGetTCBFromHandle( xTaskToSuspend );

		traceTASK_SUSPEND( pxTCB );

		/* 从就绪/延迟列表中删除任务,并将其放入挂起列表中. */
		if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ){
			/* 调整清除优先级位域 uxTopReadyPriority */
			taskRESET_READY_PRIORITY( pxTCB->uxPriority );
		}else{
			mtCOVERAGE_TEST_MARKER();
		}

		/* 任务也在等待事件吗,是也移除 */
		if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ){
			( void ) uxListRemove( &( pxTCB->xEventListItem ) );
		}else{
			mtCOVERAGE_TEST_MARKER();
		}

		vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );
	}
	taskEXIT_CRITICAL();

    /* 调度器在运行 */
	if( xSchedulerRunning != pdFALSE ){
		taskENTER_CRITICAL();
		{/* 遍历 pxDelayedTaskList,调整解锁时间值 xNextTaskUnblockTime ,以防它引用了现在处于暂停状态的任务. */
			prvResetNextTaskUnblockTime();
		}
		taskEXIT_CRITICAL();
	}else{
		mtCOVERAGE_TEST_MARKER();
	}

	if( pxTCB == pxCurrentTCB ){
		if( xSchedulerRunning != pdFALSE ){
			/* 当前任务刚刚暂停.触发pendSv,进行程序调度 */
			configASSERT( uxSchedulerSuspended == 0 );
			portYIELD_WITHIN_API();
		}else{
			/* 调度器没有运行,但是pxCurrentTCB所指向的任务刚刚被挂起,必须调整pxCurrentTCB以指向不同的任务. */
			if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks ){
				/* 没有其他任务准备好了,所以将pxCurrentTCB设置为NULL,以便在下一个任务创建时,无论它的相对优先级是什么,pxCurrentTCB都将被设置为指向它. */
				pxCurrentTCB = NULL;
			}else{
				/* 主动 做一次任务切换,将当前任务调度出去 */
				vTaskSwitchContext();
			}
		}
	}else{
		mtCOVERAGE_TEST_MARKER();
	}
}

5,任务恢复实现

void vTaskResume( TaskHandle_t xTaskToResume )
{
    TCB_t * const pxTCB = ( TCB_t * ) xTaskToResume;

	configASSERT( xTaskToResume );

	/* The parameter cannot be NULL as it is impossible to resume the
	currently executing task. */
	if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) ){
		taskENTER_CRITICAL();
		{
			/* 判断任务是否挂起 */
			if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE ){
				traceTASK_RESUME( pxTCB );

				/* 由于我们处于一个关键部分,即使调度程序被挂起,我们也可以访问就绪列表,从挂起列表移除到就绪列表. */
				( void ) uxListRemove(  &( pxTCB->xStateListItem ) );
				prvAddTaskToReadyList( pxTCB );

				/* 我们若刚刚恢复了一项更优先的任务. */
				if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ){
					/* 触发pendSv ,进行任务调度*/
					taskYIELD_IF_USING_PREEMPTION();
				}else{
					mtCOVERAGE_TEST_MARKER();
				}
			}else{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		taskEXIT_CRITICAL();
	}else{
		mtCOVERAGE_TEST_MARKER();
	}
}

 

6,认识阻塞和挂起概念区别

阻塞 挂起
延时任务列表 挂起任务列表

当一个任务当前正在等待某个外部事件的话就说它处于阻塞态

阻塞则是一种被动行为,是在等待事件或资源时任务的表现,接触阻塞的时机不可预料。

阻塞队列则是不同的事件或资源(如信号量)就有自己的队列。

阻塞(PEND)就是任务释放CPU,其他任务可以运行,一般在等待某种资源或信号量的时候出现。

任务临时暂停运行

挂起是任务的一种主动行为,因此恢复也应该要主动完成。且恢复时机需要等待恢复通知即可。

挂起队列在操作系统里可以看成一个,独立维护。

挂起(暂停)不释放CPU,如果挂起任务优先级高就永远轮不到其他任务运行。

任务进入阻塞态以后,当时机成熟时会被调度器放入运行态,重新被调度运行。

任务进入阻塞态会有一个超时时间,当超过这个超时时间任务就会退出阻塞态,即使所等待的事件还没有来临。

任务进入挂起态以后不能被调度器管理。此任务一直不会准备。

进入挂起态的任务没有超时时间

个任务调用了函数vTaskDelay()的话就会进入阻塞态,直到延时周期完成。

务在等待队列,信号量,事件组,通知或互斥信号量的时候也会进入阻塞态。

进入和退出挂起态通过调用函数vTaskSuspend()和xTaskResume()

你可能感兴趣的:(FreeRtos系统)