Linux线程调度源码分析
Linux线程调度是一种策略,在计算机资源相对固定的情况下通过某种规则动态的调度线程的运行,使其最大程度的满足程序运行的要求。内核定义了五种调度策略,通过五个调度器(结构体实例)加以实现,优先级从高到低分别是:stop_sched_class、dl_sched_class、rt_sched_class、fair_sched_class、idle_sched_class。所有的调度器都由一个入口(schedule)完成Linux复杂多变,又性能卓越的调度任务。
Linux可能随时发生调度。在用户空间,在系统调用时,在中断产生的时候,都有可能进入调度例程。虽然线程调度的时间不可确定,但执行线程调度的地方只有三个,在系统调用返回的地方,在中断例程返回的地方,及在内核主动执行schedule的地方。下面我们看看调度入口函数schedule()的实现。
线程不管是主动调用,还是从中断返回时调用schedule函数,都会发生线程的切换,一旦从此函数返回时,线程已经切换出去又切换回来了。线程调用此函数时,把自己挂起来,然后让出CPU就去执行其他线程的代码,等下一次调度回来后,线程重新唤醒并获得CPU,之后从此函数返回,继续执行后面的代码。从线程的角度看切换是无感的,完全不知道有这回事一样。我们看看调度函数的具体实现
3250-3253行,__schedule函数首先获取当前的线程指针,可能有人会问,当前线程为什么不直接取current的值,因为调用__schedule的时候有可能是在中断上下文中,所以为了安全起见,从rq里取出当前线程是比较保险。
3309行,pick_next_task函数就是线程调度策略的关键函数,每一种调度器都有自己的调度策略,根据不同的逻辑返回下一个待调度的线程。
3327行,context_switch函数执行线程上下文切换。切换详情请参见《线程切换源码分析》
调度的策略主要体现在如何选择下一个待切换的线程上,每一个调度器都有不同的实现。
调度例程从最高优先级的调度器开始逐个执行pick_next_task接口函数,一旦找到了待调度的线程,则从for_each_class循环中返回,如果一直没有找到待调度的线程,则最后的idle_sched_class将返回idle线程的指针。
内核为每个CPU核心创建一个struct rq对象,此对象管理当前CPU运行的每一个线程,线程一个时间内只能待在一个rq中,如果要切换到别的CPU上运行,就需要执行mirgation操作。线程被创建,或者在等待队列中唤醒的时候,会加入到待运行的rq中,然后在线程调度的时候由调度器选出,后调度执行。
859,867行,具体的出入队列逻辑由具体的调度器负责,每个调度器有自己的调度策略。
以上就是线程调度相关的内容(ARMv8,Kernel4.4)。如有帮助请加关注!
源码园
专注源码分析,分享研发经验
17篇原创内容
Official Account
标签: