`
jiagou
  • 浏览: 2595290 次
文章分类
社区版块
存档分类
最新评论

rt-thread线程调度器源码分析

 
阅读更多

1 前言

RT-Thread中提供的线程调度器是基于全抢占式优先级的调度,在系统中除了中断处理函数、调度器上锁部分的代码和禁止中断的代码是不可抢占的之外,系统的其他部分都是可以抢占的,包括线程调度器自身.系统总共支持256个优先级(0 ~ 255,数值越小的优先级越高,0为最高优先级,255分配给空闲线程使用,一般用户不使用。在一些资源比较紧张的系统中,可以根据情况选择只支持8个或32个优先级的系统配置)。在系统中,当有比当前线程优先级还要高的线程就绪时,当前线程将立刻被换出,高优先级线程抢占处理机进行执行。

2 线程优先级管理系统

rt-thread采用一个数组来实现线程优先级管理系统,如下图所示,RT-Thread调度器实现中包含一组,总共256个优先级队列数组(如果系统最大支持32个优先级,那么这里将是32个优先级队列数组),每个优先级队列采用双向环形链表的方式链接,255优先级队列中一般只包含一个idle线程。

其源码定义如下:

rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];

2 调度器初始化

/**
 * @ingroup SystemInit
 * This function will initialize the system scheduler
 */
void rt_system_scheduler_init(void)
{
    register rt_base_t offset;

    rt_scheduler_lock_nest = 0;//调度器嵌套锁计数器设为0

    RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("start scheduler: max priority 0x%02x\n",
                                      RT_THREAD_PRIORITY_MAX));

    for (offset = 0; offset < RT_THREAD_PRIORITY_MAX; offset ++)//所有优先级对应的线程链表初始化
    {
        rt_list_init(&rt_thread_priority_table[offset]);
    }

    rt_current_priority = RT_THREAD_PRIORITY_MAX - 1;//rt_current_prority为全局变量,初始化
    rt_current_thread = RT_NULL;//全局变量rt_current_thread初始化为空

    /* initialize ready priority group */
    rt_thread_ready_priority_group = 0;//全局变量rt_thread_ready_priority_group初始化为0

#if RT_THREAD_PRIORITY_MAX > 32
    /* initialize ready table */
    rt_memset(rt_thread_ready_table, 0, sizeof(rt_thread_ready_table));
#endif

    /* initialize thread defunct */
    rt_list_init(&rt_thread_defunct);//初始化全局空闲线程处理的回调线程链表,rt_thread_defunct为这线程链表,只在系统空闲时被空闲线程操作
}

3 启动线程调度器

/**
 * @ingroup SystemInit
 * This function will startup scheduler. It will select one thread
 * with the highest priority level, then switch to it.
 */
void rt_system_scheduler_start(void)
{
    register struct rt_thread *to_thread;
    register rt_ubase_t highest_ready_priority;
    //以下代码是查找出新高优先级的线程
#if RT_THREAD_PRIORITY_MAX == 8
    highest_ready_priority = rt_lowest_bitmap[rt_thread_ready_priority_group];
#else
    register rt_ubase_t number;
    /* find out the highest priority task */
    if (rt_thread_ready_priority_group & 0xff)
    {
        number = rt_lowest_bitmap[rt_thread_ready_priority_group & 0xff];
    }
    else if (rt_thread_ready_priority_group & 0xff00)
    {
        number = rt_lowest_bitmap[(rt_thread_ready_priority_group >> 8) & 0xff] + 8;
    }
    else if (rt_thread_ready_priority_group & 0xff0000)
    {
        number = rt_lowest_bitmap[(rt_thread_ready_priority_group >> 16) & 0xff] + 16;
    }
    else
    {
        number = rt_lowest_bitmap[(rt_thread_ready_priority_group >> 24) & 0xff] + 24;
    }

#if RT_THREAD_PRIORITY_MAX > 32
    highest_ready_priority = (number << 3) +
                             rt_lowest_bitmap[rt_thread_ready_table[number]];
#else
    highest_ready_priority = number;
#endif
#endif

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

    rt_current_thread = to_thread;//设置当前线程

    /* switch to new thread */
    rt_hw_context_switch_to((rt_uint32_t)&to_thread->sp);//此函数是与MCU相关的函数,实现切换到目的线程的功能

    /* never come back */
}


4 往调度器添加线程

/*
 * This function will insert a thread to system ready queue. The state of
 * thread will be set as READY and remove from suspend queue.
 *
 * @param thread the thread to be inserted
 * @note Please do not invoke this function in user application.
 */
void rt_schedule_insert_thread(struct rt_thread *thread)
{
    register rt_base_t temp;

    RT_ASSERT(thread != RT_NULL);

    /* disable interrupt */
    temp = rt_hw_interrupt_disable();//关中断

    /* change stat */
    thread->stat = RT_THREAD_READY;

    /* insert thread to ready list */
    rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),//往当前优先级链表中添加线程节点
                          &(thread->tlist));

    /* set priority mask */
#if RT_THREAD_PRIORITY_MAX <= 32
    RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("insert thread[%s], the priority: %d\n", 
                                      thread->name, thread->current_priority));
#else
    RT_DEBUG_LOG(RT_DEBUG_SCHEDULER,
                 ("insert thread[%s], the priority: %d 0x%x %d\n", 
                  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;

    /* enable interrupt */
    rt_hw_interrupt_enable(temp);//开中断
}

5 将线程从调度器中移除

/*
 * This function will remove a thread from system ready queue.
 *
 * @param thread the thread to be removed
 *
 * @note Please do not invoke this function in user application.
 */
void rt_schedule_remove_thread(struct rt_thread *thread)
{
    register rt_base_t temp;

    RT_ASSERT(thread != RT_NULL);

    /* disable interrupt */
    temp = rt_hw_interrupt_disable();//关中断

#if RT_THREAD_PRIORITY_MAX <= 32
    RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("remove thread[%s], the priority: %d\n", 
                                      thread->name, thread->current_priority));
#else
    RT_DEBUG_LOG(RT_DEBUG_SCHEDULER,
                 ("remove thread[%s], the priority: %d 0x%x %d\n", 
                  thread->name,
                  thread->number,
                  thread->number_mask,
                  thread->high_mask));
#endif

    /* remove thread from ready list */
    rt_list_remove(&(thread->tlist));//从队列中移除
    if (rt_list_isempty(&(rt_thread_priority_table[thread->current_priority])))//如果当前优先级链表已空
    {
#if RT_THREAD_PRIORITY_MAX > 32
        rt_thread_ready_table[thread->number] &= ~thread->high_mask;
        if (rt_thread_ready_table[thread->number] == 0)
        {
            rt_thread_ready_priority_group &= ~thread->number_mask;
        }
#else
        rt_thread_ready_priority_group &= ~thread->number_mask;
#endif
    }

    /* enable interrupt */
    rt_hw_interrupt_enable(temp);//开中断
}

6 线程调度

/**
 * @addtogroup Thread
 */

/*@{*/

/**
 * This function will perform one schedule. It will select one thread
 * with the highest priority level, then switch to it.
 */
void rt_schedule(void)
{
    rt_base_t level;
    struct rt_thread *to_thread;
    struct rt_thread *from_thread;

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

    /* check the scheduler is enabled or not */
    if (rt_scheduler_lock_nest == 0)//当前不处于线程嵌套中
    {
        register rt_ubase_t highest_ready_priority;
        //以下代码是获取当前最高优先级的线程的优先级
#if RT_THREAD_PRIORITY_MAX == 8
        highest_ready_priority = rt_lowest_bitmap[rt_thread_ready_priority_group];
#else
        register rt_ubase_t number;
        /* find out the highest priority task */
        if (rt_thread_ready_priority_group & 0xff)
        {
            number = rt_lowest_bitmap[rt_thread_ready_priority_group & 0xff];
        }
        else if (rt_thread_ready_priority_group & 0xff00)
        {
            number = rt_lowest_bitmap[(rt_thread_ready_priority_group >> 8) & 0xff] + 8;
        }
        else if (rt_thread_ready_priority_group & 0xff0000)
        {
            number = rt_lowest_bitmap[(rt_thread_ready_priority_group >> 16) & 0xff] + 16;
        }
        else
        {
            number = rt_lowest_bitmap[(rt_thread_ready_priority_group >> 24) & 0xff] + 24;
        }

#if RT_THREAD_PRIORITY_MAX > 32
        highest_ready_priority = (number << 3) +
                                 rt_lowest_bitmap[rt_thread_ready_table[number]];
#else
        highest_ready_priority = number;
#endif
#endif
        /* get switch to thread *///得到最高优先级线程
        to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,
                                  struct rt_thread,
                                  tlist);

        /* if the destination thread is not the same as current thread */
        if (to_thread != rt_current_thread)//需要线程切换
        {
            rt_current_priority = (rt_uint8_t)highest_ready_priority;//更新一些变量
            from_thread         = rt_current_thread;
            rt_current_thread   = to_thread;

            RT_OBJECT_HOOK_CALL(rt_scheduler_hook, (from_thread, to_thread));

            /* switch to new thread */
            RT_DEBUG_LOG(RT_DEBUG_SCHEDULER,
                         ("[%d]switch to priority#%d thread:%s\n",
                          rt_interrupt_nest,
                          highest_ready_priority,
                          to_thread->name));

#ifdef RT_USING_OVERFLOW_CHECK
            _rt_scheduler_stack_check(to_thread);//线程栈溢出检查
#endif

            if (rt_interrupt_nest == 0)//如果当前没有处于中断嵌套中
            {
                rt_hw_context_switch((rt_uint32_t)&from_thread->sp,//线程切换,此函数为MCU相关函数,与具体使用的MCU相关,这里不作介绍
                                     (rt_uint32_t)&to_thread->sp);
            }
            else//如果当前处于中断例程中
            {
                RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("switch in interrupt\n"));

                rt_hw_context_switch_interrupt((rt_uint32_t)&from_thread->sp,//线程切换,与rt_hw_context_switch类似
                                               (rt_uint32_t)&to_thread->sp);
            }
        }
    }

    /* enable interrupt */
    rt_hw_interrupt_enable(level);//开中断
}

7 进入临界区

此函数实现上实现的是禁止调度,也就是说,执行了此函数,调度器将不再调度线程,这个从第6章的语句if (rt_scheduler_lock_nest == 0) ...可以看出来。

/**
 * This function will lock the thread scheduler.
 */
void rt_enter_critical(void)
{
    register rt_base_t level;

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

    /*
     * the maximal number of nest is RT_UINT16_MAX, which is big
     * enough and does not check here
     */
    rt_scheduler_lock_nest ++;//调度锁计数器加1

    /* enable interrupt */
    rt_hw_interrupt_enable(level);//开中断
}

8 退出临界区

与进入临界区对应,此函数实现的是让之前禁止的调度器重新调度线程,其源码如下所示:

/**
 * This function will unlock the thread scheduler.
 */
void rt_exit_critical(void)
{
    register rt_base_t level;

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

    rt_scheduler_lock_nest --;//调度锁嵌套计数器减1

    if (rt_scheduler_lock_nest <= 0)//如果调度锁嵌套计数器小于或等于0,则置其为0
    {
        rt_scheduler_lock_nest = 0;
        /* enable interrupt */
        rt_hw_interrupt_enable(level);//开中断

        rt_schedule();//调度线程
    }
    else
    {
        /* enable interrupt */
        rt_hw_interrupt_enable(level);//开中断
    }
}


前面源码中的调度器启动rt_system_scheduler_start和调度rt_schedule的对应源码中都有使用位图来实现获取当前最高优先级线程对应的优先缓的算法,就不在这里做详细介绍,下一章将专门来讨论此算法,敬请关注.


分享到:
评论

相关推荐

    RT-Thread 1.1.0 Alpha源码

    学习RT-Thread 1.1.0 Alpha源码,可以深入理解RTOS的设计思想,了解实时操作系统如何调度任务、管理资源,并从中获取对物联网设备软件开发的洞见。同时,通过对早期版本的分析,可以对比后续版本的改进,理解技术的...

    rt-thread-3.1.2.zip

    通过深入学习和分析RT-Thread v3.1.2的源码,开发者可以掌握实时操作系统的设计原理,理解如何在嵌入式系统中实现多任务调度、并发控制以及资源管理。这对于提升物联网设备的软件质量、提高开发效率具有重要意义。...

    正点原子-精英板F103-RT-Thread,正点原子开发板,C,C++

    RT-Thread还提供了RTOS分析工具,能帮助开发者监控系统运行状态,定位性能瓶颈。 7. 实战案例: 例如,可以创建一个简单的LED闪烁程序,通过RT-Thread创建两个任务,一个负责控制LED亮,另一个负责控制LED灭,通过...

    2-RT-Thread源码及官方参考资料.zip

    - **源码分析**:通过阅读和理解源码,掌握RTOS设计思想,进行定制和调试。 结合这些资料,开发者不仅可以深入学习RT-Thread,还能掌握基于Cortex-M3的单片机开发技能,从而在嵌入式领域构建高效、可靠的系统。

    基于STM32F103标准库移植RTTHread_NANO

    5. **编写初始化函数**:在用户代码中,创建一个初始化函数来调用rtthread_init(),完成系统的初始化。可能还需要配置GPIO、串口等外设以便调试和通信。 6. **创建任务**:定义并注册应用程序需要的任务函数,使用...

    RT-Thread-0.4.0 beta2.zip

    通过解压并分析"RT-Thread-0.4.0 beta2.zip",开发者可以深入理解RT-Thread的工作原理,进行系统移植,或者在现有的硬件平台上构建基于RT-Thread的嵌入式应用。随着版本的迭代,RT-Thread的功能和性能也在不断优化,...

    LPC176x_Eclipse-RT-thread_Proj.zip

    6. 编写应用程序代码,利用RT-Thread提供的API实现任务调度、定时器、中断处理等功能。 7. 使用Eclipse的构建工具编译项目,生成可烧录的二进制文件。 六、调试与测试 1. 配置调试器,如J-Link或ST-Link,连接到LPC...

    NXP i.MX RT1052 RT-Thread实战:支持多优先级【基于Cortex-M7】

    在本文中,我们将深入探讨如何在NXP i.MX RT1052微控制器上实现RT-Thread实时操作系统,并利用其强大的Cortex-M7内核支持多优先级的任务调度。NXP i.MX RT1052是一款高性能、低延迟的跨界处理器,广泛应用于嵌入式...

    NXP i.MX RT1052 RT-Thread实战:支持多优先级【基于Cortex-M3】

    RT-Thread提供了线程、信号量、互斥锁、邮箱、消息队列等多种同步机制,支持抢占式调度和时间片轮转,确保多任务间的高效协作。其内核还包含了内存管理、电源管理、文件系统和网络协议栈,简化了开发流程。 3. **...

    联盛德W601实现中国移动OneNET云平台接入【RT-Thread工程,支持W60X系列单片机】.zip

    RT-Thread支持多线程、任务调度、内存管理等功能,确保了系统的实时性和稳定性。对于W60X系列单片机,RT-Thread的兼容性意味着开发者可以充分利用其性能,实现物联网设备的智能控制和数据交换。 中国移动OneNET云...

    STM32F103C8T6-物联网工作空间-RT-Thread.rar

    在这个项目中,RT-Thread可能已经被配置和定制,以适应空气净化器这样的特定设备需求。 STM32F103C8T6的特性包括: 1. 72MHz的工作频率,提供高速处理能力。 2. 内含64KB闪存和20KB SRAM,足够存储代码和数据。 3. ...

    【RT-Thread作品秀】智能管家精灵-电路方案

    RT-Thread使用情况概述(简要总结下应用中RT-Thread使用情况:内核部分、组件部分、软件包部分、内核、其他)(1)内核部分:调度器,信号量,libcpu/BSP。 调度器:创建多个线程来实现不同的工作。 信号量:用来同步...

    rt-source-master.zip

    在`Thread`类中,我们可以看到线程的创建、调度和同步机制;在`ClassLoader`中,我们可以理解类的加载过程,这在实现自定义类加载器或理解JVM工作原理时非常有用。 总结来说,深入学习Java JDK 1.8的rt.jar源码,...

    at_device-master_ATdevice_rtos_RTT_ATTCP_at_源码.zip

    【标题】"AT_device-master_ATdevice_rtos_RTT_ATTCP_at_源码"是一个与物联网(IoT)相关的源码库,特别适用于基于RTOS(实时操作系统)如RT-Thread的项目。这个源码包可能包含了AT命令设备驱动、TCP连接以及相关协议栈...

    CANfestival 移植STM32

    例如,使用RT-Thread的定时器服务替换原始的延时函数,或者使用RT-Thread的线程和信号量来同步和保护资源。 6. **调试与测试**:移植完成后,使用CAN分析仪或实际的CAN网络设备进行功能验证和性能测试,确保在STM32...

    java-jdk源码学习

    - JVM是Java程序运行的平台,它的主要任务是执行字节码并提供内存管理、线程调度等服务。 - 源码学习涵盖垃圾收集(GC)算法、类加载机制、字节码解释执行与即时编译(JIT)等核心部分。 - 对JVM的理解能帮助...

    STM32F0各种OS工程源码实验

    在STM32F0上使用RT-Thread,我们可以了解到如何设置系统时钟、管理内存、创建任务和线程、使用互斥锁和信号量等,并且可以体验到其易用性和灵活性。 3. **LEDArduino_LED**:这个部分可能涉及使用LED灯进行的示例...

    基于STM32单片机心率脉搏监测健康运动计步系统设计源码案例设计.zip

    8. 实时操作系统(RTOS):如果系统使用了RTOS,如FreeRTOS或RT-Thread,那么源码会包含任务调度、信号量、互斥锁等多线程管理机制,以保证系统的高效和稳定运行。 9. 电源管理:考虑到健康监测设备的便携性和续航...

    存算上机位软件详情介绍

    - **实时操作系统:**集成了RT-Thread实时操作系统,支持多核架构下的任务管理和调度。 - **图形库:**提供LVGL作为显示图形库,简化GUI的设计过程,支持在PC上进行模拟。 综上所述,知存科技提供的上机位软件涵盖...

Global site tag (gtag.js) - Google Analytics