FreeRTOS笔记(五)任务状态


上一文链接:FreeRTOS笔记(四)初识任务

01 - 任务的状态

  任务被创建后,它可能正在运行,可能暂停运行,任务有状态之分是由于调度器的存在,调度器需要决定哪些任务可以去运行,于是在FreeRTOS中任务具有4种状态,分别是就绪态、运行态、阻塞态和挂起态,它们之间的转化关系如下:

  4个状态的含义如下:
  就绪态:已经可以运行,等待调度器的切入
  运行态:正在占用CPU运行
  阻塞态:等待某个事件的到来,定时或者同步
  挂起态:退出调度系统,调度器不可见,只能使用vTaskSuspend()挂起和vTaskResume()唤醒后进入就绪态

  虽然官方文档只描述4个状态,但小白认为应该是5种状态,第5种是僵尸态,指在任务被删除后,其TCB控制块扔保留一段时间,等待内核检查和回收资源,在内核没有处理之前,任务其实并没有被完全删除,但是再也不能被调度器调度,这称为僵尸态,在Linux下的进程是存在僵尸态的,而从FreeRTOS的API中就可以看出,FreeRTOS的任务也存在僵尸态。

  要使用eTaskGetState()函数,就要在FreeRTOSConfig.h中配置INCLUDE_eTaskGetState宏为1

	#define INCLUDE_eTaskGetState			1

02 - tick时钟和调度器

  调度器本身也是一段程序,任务需要调度器安排执行顺序,那么调度器本身就需要被执行,这个执行由一个称为心跳时钟(tick)的中断触发,tick时钟的频率需要在FreeRTOSConfig.h文件中配置,单位是HZ,比如本例程中配置configTICK_RATE_HZ为1000,那么中断频时间是1000/1000 = 1ms,每隔1ms,FreeRTOS就会进入tick中断,触发调度器进行工作。

	#define configTICK_RATE_HZ				( ( TickType_t ) 1000 )

  调度器被触发后,会根据事先设定好的调度算法进行工作,FreeRTOS使用的调度算法有优先级抢占式调度和协作式调度
  优先级抢占式调度算法,给每一个任务分配一个优先级,调度器每次都选择优先级最高的任务执行,如果优先级相同,就采用时间片轮流执行,每个任务执行一个时间片后切出,再切入下一个任务。
  协作式调度算法,只可能在运行态任务进入阻塞态或是运行态任务显式调用taskYIELD()主动让出CPU时,才会进行上下文切换。
  调度算法的配置也是在FreeRTOSConfig.h中进行。

	#define configUSE_PREEMPTION			1	//0-协作调度,1-抢占式调度

03 - 任务状态测试

  下面用优先级抢占式调度算法来测试一下任务的各种状态,其中挂起和唤醒的API如下:

项目 Value
vTaskSuspend() 挂起一个任务
vTaskResume() 唤醒一个任务

   测试内容:一共有5个任务,分别是start和ABCD,start优先级最高,其余优先级递增,任务的工作如下:
   start:负责创建另外4个任务,输出所有任务的状态,然后删除自己
   A:输出所有任务的状态,打开LED
   B:输出所有任务的状态,关闭LED,使用vTaskDelay()阻塞自己
   C:输出所有任务的状态使用vTaskDelay()阻塞自己,然后间隔使用vTaskResume唤醒D
   D:输出所有任务的状态,使用vTaskSuspend()挂起自己

/* start 任务 */
void start_task(void *pParam)
{
	//进入临界区
	taskENTER_CRITICAL();
	
	xTaskCreate( (TaskFunction_t)a_task,
				 (const char*)"a_task",
				 (uint16_t)A_STACK_SIZE,
				 (void*)NULL,
				 (UBaseType_t)A_TASK_PRIO,
				 (TaskHandle_t*)&aTask_Handler
	);
				 
	xTaskCreate( (TaskFunction_t)b_task,
				 (const char*)"b_task",
				 (uint16_t)B_STACK_SIZE,
				 (void*)NULL,
				 (UBaseType_t)B_TASK_PRIO,
				 (TaskHandle_t*)&bTask_Handler
	);
	
	xTaskCreate( (TaskFunction_t)c_task,
				 (const char*)"c_task",
				 (uint16_t)C_STACK_SIZE,
				 (void*)NULL,
				 (UBaseType_t)C_TASK_PRIO,
				 (TaskHandle_t*)&cTask_Handler
	);
			
	xTaskCreate( (TaskFunction_t)d_task,
				 (const char*)"d_task",
				 (uint16_t)D_STACK_SIZE,
				 (void*)NULL,
				 (UBaseType_t)D_TASK_PRIO,
				 (TaskHandle_t*)&dTask_Handler
	);
	
	
	print_state("start",eTaskGetState(StartTask_Handler));
	print_state("A",eTaskGetState(aTask_Handler));
	print_state("B",eTaskGetState(bTask_Handler));
	print_state("C",eTaskGetState(cTask_Handler));
	print_state("D",eTaskGetState(dTask_Handler));
	printf("\r\n");

	//退出临界区			 
	taskEXIT_CRITICAL();
				 
	//删除自己
	vTaskDelete(NULL);
}	

/* A 任务 */
void a_task(void *pParam)
{
	for(;;)
	{
		print_all_state("A");
		
		//打开LED
		GPIO_ResetBits(GPIOF,GPIO_Pin_9 | GPIO_Pin_10);
	}
}		

/* B 任务 */
void b_task(void *pParam)
{
	for(;;)
	{
		//输出
		print_all_state("B");
		
		//关闭LED
		GPIO_SetBits(GPIOF,GPIO_Pin_9 | GPIO_Pin_10);
		
		//阻塞自己
		vTaskDelay(10);
	}	
}		

/* C 任务 */
void c_task(void *pParam)
{
	for(;;)
	{
		//输出
		print_all_state("C");
		
		//阻塞自己
		vTaskDelay(10);
		
		//唤醒D
		vTaskResume(dTask_Handler);
	}	
}		

/* D 任务 */
void d_task(void *pParam)
{
	for(;;)
	{
		//输出
		print_all_state("D");
		
		//挂起自己
		vTaskSuspend(NULL);
	}	
}		

  其中print_all_state()和print_state()是为了方便输出状态,代码如下:

static void print_state(char *msg,eTaskState state)
{
	printf("%s-",msg);
	switch(state)
	{
		case eRunning:	printf("run");break;
		case eReady:	printf("ready");break;
		case eBlocked:	printf("block");break;
		case eSuspended:printf("suspend");break;
		case eDeleted:	printf("delete");break;
		default:		printf("5");break;
	}
	printf("  ");
}

static void print_all_state(char *msg)
{
		taskENTER_CRITICAL();
		
		printf("%s:",msg);
		
		print_state("start",eTaskGetState(StartTask_Handler));
		print_state("A",eTaskGetState(aTask_Handler));
		print_state("B",eTaskGetState(bTask_Handler));
		print_state("C",eTaskGetState(cTask_Handler));
		print_state("D",eTaskGetState(dTask_Handler));
	
		printf("\r\n");
				 
		taskEXIT_CRITICAL();		
}

  运行结果

  因为延迟太短,看不到LED的闪烁,但是从串口可以看出,各个任务有序运行,每个状态都出现了,状态之间的转换几乎在一瞬间,运行时序图可以简述如下:

04 - 总结

  • 任务有4种(5种)状态,分别为就绪态、运行态、阻塞态、挂起态(僵尸态)
  • 调度器程序在每个tick时钟中断里被执行
  • FreeRTOS调度器有两种调度算法,抢占式和协作式

猜你喜欢

转载自blog.csdn.net/Hxj_CSDN/article/details/84960220
今日推荐