RT-Thread内核实现(三):空闲线程与阻塞延时的实现

空闲函数 idle

  • 如果没有其它线程可以运行, RTOS 都会为 CPU 创建一个空闲线程,这个时候 CPU 就运行空闲线程。 在 RTThread 中,空闲线程是系统在初始化的时候创建的优先级最低的线程,空闲线程主体主要是做一些系统内存的清理工作。
  • 相关定义。idle.c
#define IDLE_THREAD_STACK_SIZE      512 	// 空闲线程的栈大小

ALIGN(RT_ALIGN_SIZE)
static rt_uint8_t rt_thread_stack[IDLE_THREAD_STACK_SIZE];	// 空闲线程的栈

struct rt_thread idle;		// 空闲线程的线程控制块

extern rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];

rt_ubase_t  rt_idletask_ctr = 0;

void rt_thread_idle_entry(void *parameter)
{
    parameter = parameter;
    while (1)
    {
        rt_idletask_ctr ++;	// 简单的计数
    }
}

/**
 * @ingroup SystemInit
 *
 * 初始化空闲线程,启动空闲线程
 *
 * @note 当系统初始化的时候该函数必须被调用
 */
void rt_thread_idle_init(void)
{
    
    /* 初始化线程 */
    rt_thread_init(&idle,
                   "idle",
                   rt_thread_idle_entry,
                   RT_NULL,
                   &rt_thread_stack[0],
                   sizeof(rt_thread_stack));
    
	/* 将线程插入到就绪列表,优先级最低 */
    rt_list_insert_before( &(rt_thread_priority_table[RT_THREAD_PRIORITY_MAX-1]),&(idle.tlist) );
}

阻塞延时

  • 每个线程控制块中加入rt_ubase_t remaining_tick属性,表示该线程剩下的tick数。
  • SysTick_Handler 中断服务函数中,扫描就绪列表中所有线程的remaining_tick,如果不为0,则减1。然后执行任务调度函数。
void SysTick_Handler(void)
{
    /* 进入中断 */
    rt_interrupt_enter();

    rt_tick_increase();

    /* 离开中断 */
    rt_interrupt_leave();
}

void rt_tick_increase(void)
{
    rt_ubase_t i;
    struct rt_thread *thread;
    rt_tick ++;

	/* 扫描就绪列表中所有线程(idle线程不应该判断)的remaining_tick,如果不为0,则减1 */
	for(i=0; i < 2; i++)
	{
            thread = rt_list_entry( rt_thread_priority_table[i].next,
                                     struct rt_thread,
                                     tlist);
            if(thread->remaining_tick > 0)
            {
                thread->remaining_tick --;
            }
            
	}
    
    /* 系统调度 */
	rt_schedule();
}

  • 在调度函数中判断其他线程的remaining_tick,如果有等于0的则切换到该线程,如果没有则判断当前线程是否要进入延时状态,如果是,执行空闲线程,否则就不进行任何切换。(只适用于本章节环境)
/* 系统调度 */
void rt_schedule(void)
{
	struct rt_thread *to_thread;
	struct rt_thread *from_thread;
                                 
	/* 如果当前线程是空闲线程,那么就去尝试执行线程1或者线程2,
       看看他们的延时时间是否结束,如果线程的延时时间均没有到期,
       那就返回继续执行空闲线程 */
	if( rt_current_thread == &idle )
	{
		if(rt_flag1_thread.remaining_tick == 0)
		{            
            from_thread = rt_current_thread;
            to_thread = &rt_flag1_thread;
            rt_current_thread = to_thread;
		}
		else if(rt_flag2_thread.remaining_tick == 0)
		{
            from_thread = rt_current_thread;
            to_thread = &rt_flag2_thread;
            rt_current_thread = to_thread;
		}
		else
		{
			return;		/* 线程延时均没有到期则返回,继续执行空闲线程 */
		} 
	}
	else
	{
		/*如果当前线程是线程1或者线程2的话,检查下另外一个线程,如果另外的线程不在延时中,就切换到该线程
        否则,判断下当前线程是否应该进入延时状态,如果是的话,就切换到空闲线程。否则就不进行任何切换 */
		if(rt_current_thread == &rt_flag1_thread)
		{
			if(rt_flag2_thread.remaining_tick == 0)
			{
                from_thread = rt_current_thread;
                to_thread = &rt_flag2_thread;
                rt_current_thread = to_thread;
			}
			else if(rt_current_thread->remaining_tick != 0)
			{
                from_thread = rt_current_thread;
                to_thread = &idle;
                rt_current_thread = to_thread;
			}
			else 
			{
				return;		/* 返回,不进行切换,因为两个线程都处于延时中 */
			}
		}
		else if(rt_current_thread == &rt_flag2_thread)
		{
			if(rt_flag1_thread.remaining_tick == 0)
			{
                from_thread = rt_current_thread;
                to_thread = &rt_flag1_thread;
                rt_current_thread = to_thread;
			}
			else if(rt_current_thread->remaining_tick != 0)
			{
                from_thread = rt_current_thread;
                to_thread = &idle;
                rt_current_thread = to_thread;
			}
			else 
			{
				return;		/* 返回,不进行切换,因为两个线程都处于延时中 */
			}
		}
	}
	
	/* 产生上下文切换 */
	rt_hw_context_switch((rt_uint32_t)&from_thread->sp,(rt_uint32_t)&to_thread->sp);	
	
}
  • 通过库函数配置SysTick中断频率,优先级。在main函数中调用。下面配置 25MHz / (25MHz / 100) = 100Hz。即SysTick中断10ms一次。
/* 设置SysTick中断频率 */
SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);

__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
  if ((ticks - 1) > SysTick_LOAD_RELOAD_Msk)  return (1);      /* Reload value impossible */

  SysTick->LOAD  = ticks - 1;                                  /* set reload register */
  NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* set Priority for Systick Interrupt */
  SysTick->VAL   = 0;                                          /* Load the SysTick Counter Value */
  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                   SysTick_CTRL_TICKINT_Msk   |
                   SysTick_CTRL_ENABLE_Msk;                    /* Enable SysTick IRQ and SysTick Timer */
  return (0);                                                  /* Function successful */
}

工程文件

空闲线程、阻塞延时

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章