zoukankan      html  css  js  c++  java
  • RT-Thread内核之线程调度(三)

    4.RT-Thread中的线程?
    /**
     * 线程结构
     */
    struct rt_thread {
        /** Object对象 */
        char        name[RT_NAME_MAX];                      /**< 线程的名字 */
        rt_uint8_t  type;                                   /**< 对象的类型 */
        rt_uint8_t  flags;                                  /**< 线程的标志 */
    #ifdef RT_USING_MODULE
        void       *module_id;                              /**< 应用模块的ID */
    #endif
        rt_list_t   list;                                   /**< 对象链表 */
        rt_list_t   tlist;                                  /**< 线程链表 */
        void       *sp;                                     /**< 栈顶指针 */
        void       *entry;                                  /**< 入口函数 */
        void       *parameter;                              /**< 附加參数 */
        void       *stack_addr;                             /**< 栈底地址 */
        rt_uint16_t stack_size;                             /**< 线程栈的大小 */
        rt_err_t    error;                                  /**< 线程执行的错误码 */
        rt_uint8_t  stat;                                   /**< 线程的状态 */
        rt_uint8_t  current_priority;                       /**< 线程的当前优先级 */
        rt_uint8_t  init_priority;                          /**< 线程的初始优先级 */
     
    #if RT_THREAD_PRIORITY_MAX > 32
        rt_uint8_t  number;         /**< 线程优先级相应的组号: current_priority >> 3 */
        rt_uint8_t  high_mask;      /**< 线程位号掩码: (1 << 位号) 位号: (current_priority & 7) */
    #endif
        rt_uint32_t number_mask;    /**< 组号掩码: (1 << 组号) */
    #if defined(RT_USING_EVENT)
        rt_uint32_t event_set;      /** 线程的事件集 */
        rt_uint8_t  event_info;     /** 多事件的逻辑关系: 与/或/非 */
    #endif
        rt_ubase_t  init_tick;                              /**< 线程初始化的执行滴答值 */
        rt_ubase_t  remaining_tick;                         /**< 线程执行的剩余滴答数 */
        struct rt_timer thread_timer;                       /**< 内嵌的线程定时器 */
        void (*cleanup)(struct rt_thread *tid);             /**< 线程退出时的清除函数 */
        rt_uint32_t user_data;                              /**< 私实用户数据 */
    };
    总的来看。线程皆有由几类成员组成:object,栈相关信息。优先级信息,事件,定时器信息,私有数据指针。在RT-Thread中提供的线程接口函数都是环绕线程的各种状态展开的。

    /*
     * 线程的状态定义
     */
    #define RT_THREAD_INIT                  0x00                /**< 初始化状态 */
    #define RT_THREAD_READY                 0x01                /**< 就绪状态 */
    #define RT_THREAD_SUSPEND               0x02                /**< 挂起状态 */
    #define RT_THREAD_RUNNING               0x03                /**< 执行状态 */
    #define RT_THREAD_BLOCK                 RT_THREAD_SUSPEND   /**< 堵塞状态 */
    #define RT_THREAD_CLOSE                 0x04                /**< 关闭/结束状态 */

    处于初始化状态的接口函数有:rt_thread_init,rt_thread_create
    这两个函数的差别在于一个是静态的初始化一个线程实体,还有一个是动态的创建线程实体再来初始化。


    /*******************************************************************************************
    ** 函数名称: rt_thread_init
    ** 函数功能: 静态初始化线程实例
    ** 入口參数: thread 线程对象句柄
    **    name 线程的名字
    **    entry 线程的入口函数
    **    parameter 附加參数
    **    stack_start 栈底指针
    **    stack_size 栈的大小
    **    priority 线程的优先级
    **    tick 线程的初始滴答数(能执行的时间片值)
    ** 返 回 值: 成功返回RT_EOK
    ** 调    用: rt_thread_init
    *******************************************************************************************/
    rt_err_t rt_thread_init(struct rt_thread *thread,
                               const char       *name,
                               void (*entry)(void *parameter),
                               void* parameter,
                               void* stack_start,
                               rt_uint32_t stack_size,
                               rt_uint8_t priority,
                               rt_uint32_t tick)
    {
        /** 參数检查 */
        RT_ASSERT(thread != RT_NULL);
        RT_ASSERT(stack_start != RT_NULL);
        /** 初始化线程内嵌的对象结构 */
        rt_object_init((rt_object_t)thread, RT_Object_Class_Thread, name);
        /** 初始化线程实例 */
        return _rt_thread_init(thread,
                               name,
                               entry,
                               parameter,
                               stack_start,
                               stack_size,
                               priority,
                               tick);
    }


    /*******************************************************************************************
    ** 函数名称: rt_thread_create
    ** 函数功能: 动态的创建线程
    ** 入口參数: name 线程的名字
    **    entry 线程的入口
    **    parameter 附加參数
    **    stack_size 线程栈的大小
    **    priority 线程的优先级
    **    tick 线程的初始化滴答数
    ** 返 回 值: 线程对象句柄
    ** 调    用:
    *******************************************************************************************/
    rt_thread_t rt_thread_create(const char *name,
                                 void (*entry)(void *parameter),
                                 void       *parameter,
                                 rt_uint32_t stack_size,
                                 rt_uint8_t  priority,
                                 rt_uint32_t tick)
    {
        struct rt_thread *thread;
        void *stack_start;
        /** 分配线程对象 */
        thread = (struct rt_thread *)rt_object_allocate(RT_Object_Class_Thread, name);
        if (thread == RT_NULL)
            return RT_NULL;
        /** 分配线程的栈 */
        stack_start = (void *)RT_KERNEL_MALLOC(stack_size);
        if (stack_start == RT_NULL) {
            rt_object_delete((rt_object_t)thread);
            return RT_NULL;
        }
        /** 初始化线程实例 */
        _rt_thread_init(thread,
                        name,
                        entry,
                        parameter,
                        stack_start,
                        stack_size,
                        priority,
                        tick);
        return thread;
    }

    终于都调用到_rt_thread_init函数:
    /******************************************************************************************* 
    ** 函数名称: _rt_thread_init
    ** 函数功能: 初始化线程实例
    ** 入口參数: thread 线程对象句柄
    **    name 线程的名字
    **    entry 线程的入口函数
    **    parameter 附加參数
    **    stack_start 栈底指针
    **    stack_size 栈的大小
    **    priority 线程的优先级
    **    tick 线程的初始滴答数(能执行的时间片值)
    ** 返 回 值: 成功返回RT_EOK
    ** 调    用: rt_thread_init
    *******************************************************************************************/
    static rt_err_t _rt_thread_init(struct rt_thread* thread,
                                     const char* name,
                                     void (*entry)(void *parameter),
                                     void * parameter,
                                     void * stack_start,
                                     rt_uint32_t stack_size,
                                     rt_uint8_t  priority,
                                     rt_uint32_t tick)
    {
        /** 初始化线程链表节点成员 */
        rt_list_init(&(thread->tlist));
        thread->entry = (void *)entry;
        thread->parameter = parameter;
        thread->stack_addr = stack_start;
        thread->stack_size = (rt_uint16_t)stack_size;
        /** 初始化线程的栈 */
        rt_memset(thread->stack_addr, '#', thread->stack_size);
        thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,
            (void *)((char *)thread->stack_addr + thread->stack_size - 4),
            (void *)rt_thread_exit);
        RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX);
        thread->init_priority    = priority;
        thread->current_priority = priority;
        thread->init_tick      = tick;
        thread->remaining_tick = tick;
        thread->error = RT_EOK;
     
        /** 创建线程时,线程处于INIT状态 */
        thread->stat  = RT_THREAD_INIT;
        thread->cleanup   = 0;
        thread->user_data = 0;
        /** 初始化线程内嵌的定时器 */
        rt_timer_init(&(thread->thread_timer),
                      thread->name,
                      rt_thread_timeout,
                      thread,
                      0,
                      RT_TIMER_FLAG_ONE_SHOT);
        return RT_EOK;
    }
    在这个函数中有几点须要注意:
    1.线程的栈是怎样初始化的?
    线程的栈是这样布局的:
    -----------
    | Entry   |        <--- 线程的入口函数
    -----------    
    |  LR     |        <--- 返回地址
    -----------
    |  R12    |        <--- 通用寄存器
    -----------
    |  R11    |
    -----------
    |  R10    |
    -----------
    |  R9     |
    -----------
    |  R8     |
    -----------
    |  R7     |
    -----------
    |  R6     |
    -----------
    |  R5     |
    -----------
    |  R4     |
    -----------
    |  R3     |
    -----------
    |  R2     |
    -----------
    |  R1     |
    -----------
    |  R0     |
    -----------
    |  CPSR   |    <--- 当前程序状态寄存器
    -----------    
    |  SPSR   |    <--- 保存程序状态寄存器
    -----------

    2.线程内嵌的定时器的目的?
    线程内嵌定时器来实现线程状态的改变。比方当须要让线程休眠多少个时钟滴答时,能够将线程设置为挂起状态。然后设置定时器的超时时间启动定时器。这样当定时器超市就能唤醒线程

    3.此时线程是否具备了执行条件?
    初始化后线程的状态为INIT状态,并不能执行,要转换成就绪状态需调用rt_thread_startup


    设置线程为就绪状态的接口函数有rt_thread_control。rt_thread_resume。rt_thread_timeout
    rt_thread_control
        rt_schedule_insert_thread
            thread->stat = RT_THREAD_READY


    rt_thread_resume
        rt_schedule_insert_thread
            thread->stat = RT_THREAD_READY

    rt_thread_timeout
        rt_schedule_insert_thread
            thread->stat = RT_THREAD_READY
    能够发现设置线程为就绪状态的接口函数实际为rt_schedule_insert_thread
    /*********************************************************************************************************
    ** 函数名称: rt_schedule_insert_thread
    ** 函数功能: 将线程插入到就绪队列中
    ** 入口參数: thread 线程对象句柄
    ** 返 回 值: 无
    ** 调    用:
    *********************************************************************************************************/
    void rt_schedule_insert_thread(struct rt_thread* thread)
    {
        register rt_base_t temp;
        /** 參数检查 */
        RT_ASSERT(thread != RT_NULL);
        /** 禁止全局中断 */
        temp = rt_hw_interrupt_disable();
        /** 设置线程的状态为就绪态 */
        thread->stat = RT_THREAD_READY;
        /** 将线程插入到优先级队列中 */
        rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),
                              &(thread->tlist));
    #if RT_THREAD_PRIORITY_MAX <= 32
        RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("insert thread[%.*s], the priority: %d ",
                                          RT_NAME_MAX, thread->name, thread->current_priority));
    #else
        RT_DEBUG_LOG(RT_DEBUG_SCHEDULER,
                     ("insert thread[%.*s], the priority: %d 0x%x %d ",
                      RT_NAME_MAX,
                      thread->name,
                      thread->number,
                      thread->number_mask,
                      thread->high_mask));
    #endif
        /** 设置就绪表和就绪组 */
    #if RT_THREAD_PRIORITY_MAX > 32
        rt_thread_ready_table[thread->number] |= thread->high_mask;
    #endif
        rt_thread_ready_priority_group |= thread->number_mask;
        /** 使能全局中断 */
        rt_hw_interrupt_enable(temp);
    }
    在函数中除了将线程设置为就绪状态外,还有几个动作须要关注:
    1.将线程增加线程优先级链表中。在RT-Thread支持的优先级个数能够为32或256,但系统所支持的线程数目并没有限制。

    因此,处于同一优先级的线程是能够多个的,这些线程将以链表连接起来。这些具有同样优先级的线程的调度方式为时间片调度。

    rt_thread_priority_table[256]
    ----------
    |   0    |----->线程2 ---> 线程5 --->...
    ----------
    |   1    |
    ----------
    .........
    ----------
    |   253  | ---> 线程100 --->线程3
    ----------
    |   254  |
    ----------
    |   255  | ---> 线程50
    ----------

    2.设置了全局的就绪表和就绪组


    设置线程为挂起状态的接口函数有rt_thread_startup,rt_thread_suspend


    rt_thread_startup
        thread->stat = RT_THREAD_SUSPEND        /** 设置线程的状态为挂起状态 */

    rt_thread_suspend
        thread->stat = RT_THREAD_SUSPEND
        rt_schedule_remove_thread

    设置线程为挂起状态的接口函数有rt_thread_exit。rt_thread_detach,rt_thread_delete
    rt_thread_delete
        rt_schedule_remove_thread
        thread->stat = RT_THREAD_CLOSE
        rt_list_insert_after(&rt_thread_defunct, &(thread->tlist))

    rt_thread_detach
        rt_schedule_remove_thread
        rt_timer_detach
        thread->stat = RT_THREAD_CLOSE
        rt_object_detach

    rt_thread_exit
        rt_schedule_remove_thread
        thread->stat = RT_THREAD_CLOSE
        rt_timer_detach

  • 相关阅读:
    043_MySQL 索引原理 与 慢查询优化
    042_MySQL 之【视图】【触发器】【存储过程】【函数】【事物】【数据库锁】【数据库备份】
    041_SQL逻辑查询语句执行顺序
    039_MySQL 数据操作
    040_数据库设计三范式
    039_MySQL_多表查询
    039_MySQL_单表查询
    038_MySQL 表的操作
    MySQL 存储引擎
    037_MySQL操作
  • 原文地址:https://www.cnblogs.com/jzssuanfa/p/6720031.html
Copyright © 2011-2022 走看看