RT-Thread内核实现(六):时间片

整体思想

  • 假如A、B两个线程优先级相同,A先启动,只要A不主动让出CPU,线程B就没机会执行。
  • 时间片就是为了解决相同优先级下多线程的并发问题。

线程控制块

  • 添加rt_ubase_t init_tick属性,remaining_tick记录剩余的时间片。
struct rt_thread
{
    /* rt 对象 */
    char        name[RT_NAME_MAX];    /* 对象的名字 */
    rt_uint8_t  type;                 /* 对象类型 */
    rt_uint8_t  flags;                /* 对象的状态 */
    rt_list_t   list;                 /* 对象的列表节点 */
    
    rt_list_t   tlist;            /* 线程链表节点 */
    
	void        *sp;	          /* 线程栈指针 */
	void        *entry;	          /* 线程入口地址 */
	void        *parameter;	      /* 线程形参 */	
	void        *stack_addr;      /* 线程起始地址 */
	rt_uint32_t stack_size;       /* 线程栈大小,单位为字节 */
    
    rt_ubase_t  init_tick;          /* 初始时间片 */
    rt_ubase_t  remaining_tick;     /* 剩余时间片 */
    
    rt_uint8_t current_priority;    /* 当前优先级 */
    rt_uint8_t init_priority;       /* 初始优先级 */
    rt_uint32_t number_mask;        /* 当前优先级掩码 */
    
    rt_err_t    error;              /* 错误码 */
    
    rt_uint8_t stat;                /* 线程的状态 */
    
    struct rt_timer thread_timer;   /* 内置的线程定时器 */
};
typedef struct rt_thread *rt_thread_t;

线程初始化函数修改

/* 初始化线程 */
    rt_thread_init( &rt_flag1_thread,                   /* 线程控制块 */
                    "rt_flag1_thread",                  /* 线程名字,字符串形式 */
                    flag1_thread_entry,                 /* 线程入口地址 */    
                    RT_NULL,                            /* 线程形参 */
                    &rt_flag1_thread_stack[0],          /* 线程栈起始地址 */    
                    sizeof(rt_flag1_thread_stack),      /* 线程栈大小 */
                    2,                                  /* 线程优先级 */
                    4);                                 /* 时间片 */

时基更新函数修改

  • 如果时间片到了就重置时间片,调用rt_thread_yield()让出CPU。
void rt_tick_increase(void)
{
    struct rt_thread *thread;
    rt_tick ++;
    
    thread = rt_thread_self();
    --thread->remaining_tick;
    
    if(thread->remaining_tick == 0){
        /* 重置时间片 */
        thread->remaining_tick = thread->init_tick;
        
        /* 让出CPU */
        rt_thread_yield();
    }
    
    /* 扫描系统定时器列表 */
	rt_timer_check();
}
  • 函数rt_err_t rt_thread_yield(void)
/**
 * 该函数将让当前线程让出处理器,调度器选择最高优先级的线程运行。当前让出处理器之后,
 * 当前线程还是在就绪态。
 *
 * @return RT_EOK
 */
rt_err_t rt_thread_yield(void)
{
    register rt_base_t level;
    struct rt_thread *thread;

    /* 关中断 */
    level = rt_hw_interrupt_disable();

    /* 获取当前线程的线程控制块 */
    thread = rt_current_thread;
    
    /* 如果线程在就绪态,且同一个优先级下不止一个线程 */
    if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_READY &&
        thread->tlist.next != thread->tlist.prev)
    {
        /* 将时间片耗完的线程从就绪列表移除 */
        rt_list_remove(&(thread->tlist));
        
        /* 将线程插入到该优先级下的链表的尾部 */
        rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),
                              &(thread->tlist));

        /* 开中断 */
        rt_hw_interrupt_enable(level);

        /* 执行调度 */
        rt_schedule();

        return RT_EOK;
    }

    /* 开中断 */
    rt_hw_interrupt_enable(level);

    return RT_EOK;
}

工程代码

12_time_slice

你可能感兴趣的:(RTOS)