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 */
}

工程文件

空閒線程、阻塞延時

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