【RT-Thread】内核线程调度算法(基于位图的线程调度算法)

  • 在实时操作系统中,对时间的要求度很高,所以在线程调度算法RT-Thread采用的是位图调度算法,时间复杂度为O(1)。本篇采用最大优先级为32的情况进行讲解,256与之类似。
/* Maximum priority level, 32 */
rt_uint32_t rt_thread_ready_priority_group;  //[0:31]每一位代表一个线程优先级

1. rt_thread_ready_priority_group是一个32位全局变量,如果有新的线程创建,则会把对应的线程优先级在rt_thread_ready_priority_group对应的bit位置1。

例如:新创建的线程优先级为8,则由1,2可以看出将rt_thread_ready_priority_group的第8位置位1。

2.接下来在rt_schedule中看rt_thread_ready_priority_group变量的使用。

const rt_uint8_t __lowest_bit_bitmap[] =
{
    /* 00 */ 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 10 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 20 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 30 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 40 */ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 50 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 60 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 70 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 80 */ 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 90 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* A0 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* B0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* C0 */ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* D0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* E0 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* F0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
};

/**
 * This function finds the first bit set (beginning with the least significant bit)
 * in value and return the index of that bit.
 *
 * Bits are numbered starting at 1 (the least significant bit).  A return value of
 * zero from any of these functions means that the argument was zero.
 *
 * @return return the index of the first bit set. If value is 0, then this function
 * shall return 0.
 */
int __rt_ffs(int value)
{
    if (value == 0) return 0;
    if (value & 0xff)
        return __lowest_bit_bitmap[value & 0xff] + 1;

    if (value & 0xff00)
        return __lowest_bit_bitmap[(value & 0xff00) >> 8] + 9;

    if (value & 0xff0000)
        return __lowest_bit_bitmap[(value & 0xff0000) >> 16] + 17;

    return __lowest_bit_bitmap[(value & 0xff000000) >> 24] + 25;
}

源码中的__lowest_bit_bitmap数组是根据线程优先级进行提前推算出来的。value也即rt_thread_ready_priority_group。

例如: value = 8, 8的二进制为1000,从右往左数,第一个为1的位在第3位(默认从0开始)。所以__lowest_bit_bitmap[8]为3。

           value = 5,   5的二进制为101,从右往走数,第一个为1的位在第0位。所以__lowest_bit_bitmap[5]为0。

   value = 16,   5的二进制为10000,从右往走数,第一个为1的位在第4位。所以__lowest_bit_bitmap[16]为4。

 由数组可以找到rt_thread_ready_priority_group数值对应的最高优先级数为多少,也就找到了最高优先级线程所在的链表。

而通过3求得的highest_ready_priority有如下作用:

RT-Thread中的TCB数据结构,我们暂时只记住tlist成员:

struct rt_thread
{
    /* rt object */
    char        name[RT_NAME_MAX];                      /**< the name of thread */
    rt_uint8_t  type;                                   /**< type of object */
    rt_uint8_t  flags;                                  /**< thread's flags */

#ifdef RT_USING_MODULE
    void       *module_id;                              /**< id of application module */
#endif

    rt_list_t   list;                                   /**< the object list */
    rt_list_t   tlist;                                  /**< the thread list */

    /* stack point and entry */
    void       *sp;                                     /**< stack point */
    void       *entry;                                  /**< entry */
    void       *parameter;                              /**< parameter */
    void       *stack_addr;                             /**< stack address */
    rt_uint32_t stack_size;                             /**< stack size */

    /* error code */
    rt_err_t    error;                                  /**< error code */

    rt_uint8_t  stat;                                   /**< thread status */

    /* priority */
    rt_uint8_t  current_priority;                       /**< current priority */
    rt_uint8_t  init_priority;                          /**< initialized priority */
#if RT_THREAD_PRIORITY_MAX > 32
    rt_uint8_t  number;
    rt_uint8_t  high_mask;
#endif
    rt_uint32_t number_mask;

#if defined(RT_USING_EVENT)
    /* thread event */
    rt_uint32_t event_set;
    rt_uint8_t  event_info;
#endif

#if defined(RT_USING_SIGNALS)
    rt_sigset_t     sig_pending;                        /**< the pending signals */
    rt_sigset_t     sig_mask;                           /**< the mask bits of signal */

    void            *sig_ret;                           /**< the return stack pointer from signal */
    rt_sighandler_t *sig_vectors;                       /**< vectors of signal handler */
    void            *si_list;                           /**< the signal infor list */
#endif

    rt_ubase_t  init_tick;                              /**< thread's initialized tick */
    rt_ubase_t  remaining_tick;                         /**< remaining tick */

    struct rt_timer thread_timer;                       /**< built-in thread timer */

    void (*cleanup)(struct rt_thread *tid);             /**< cleanup function when thread exit */

    /* light weight process if present */
#ifdef RT_USING_LWP
    void        *lwp;
#endif

    rt_uint32_t user_data;                             /**< private user data beyond this thread */
};

优先级链表:

rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX]; //每一个优先级对应一个链表。是通过rt_thread结构中的tlist成员来进行相同优先级线程的链接

通过tlist成员来获取对应的rt_thread结构体的首地址信息。

/* get switch to thread */
/*/ to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next, struct rt_thread, tlist);

                   
#define rt_list_entry(node, type, member) \ rt_container_of(node, type, member) #define rt_container_of(ptr, type, member) \ //在linux内核中该用法有很多 ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))
该成员所在的地址 - 该成员相对于结构体偏移的地址 = 该结构体的首地址

综上,就可以找到对应的优先级数最高的线程进行调度。由于表是提前计算好的,所以时间复杂度为o(1)。

猜你喜欢

转载自www.cnblogs.com/Raowz/p/13163120.html