linux线程调度

实时与非实时操作系统

实时操作系统对一些中断的响应的时效性非常高,即使在内核态的时候。非实时反之。目前像VxWorks属于实时操作系统,大家常用的windows和linux都属于非实时操作系统,也叫做分时操作系统。响应实时的表现主要是抢占,抢占通过优先级来控制,优先级高的任务最先占用CPU。

Linux系统调度管理算法

Linux系统中常见的几种调度调度管理算法为SCHED_NORMAL、SCHED_FIFO、SCHED_RR

  • SCHED_NORMAL 用于普通线程
  • SCHED_FIFO、SCHED_RR 用于实时线程,优先级高于SCHED_NORMAL

内核中区分普通线程与实时线程是根据线程的优先级,实时线程拥有实时优先级(real-time priority),默认取值为0~99,数值越高优先级越高,而普通线程只具有nice值,nice值映射到用户层的取值范围为-20~+19,数值越高优先级越低,默认初始值为0 ,子线程会继承父线程的优先级。

对于实时线程,Linux系统会尽量使其调度延时在一个时间期限内,但是不能保证总是如此,不过正常情况下已经可以满足比较严格的时间要求了。

SCHED_NORMAL

2.6之后版本的Linux中SCHED_NORMAL使用的是Linux内核在2.6.23版本中引入的CFS(Complete Fair Scheduler) 调度管理程序。CFS与之前的调度不同的是,线程的优先级与时间片之间并没有一个固定的关系,而是影响该线程在整个系统CPU运行时间中占有比例的一个因素。比如有两个线程,对应的nice值分别为0(普通线程)和+19(低优先级线程),那么普通线程将会占有19/20×100%的CPU时间,而低优先级线程将会占有1/20×100%的CPU时间(具体数值只做举例说明用,Linux内核中的计算出来的数值会不一样)。而如果同时运行的只有两个相同优先级的线程,那么他们分到的CPU时间各是50%。这样每个线程能够分配到的CPU时间占有比例跟系统当前的负载(所有处于运行态的线程数以及各线程的优先级)有关,同一个线程在他本身优先级不变的情况下分到的CPU时间占比会根据系统负载变化而发生变化,也即与时间片没有一个固定的对应关系。

简而言之SCHED_NORMAL的管理策略就是:根据nice值来计算各个线程占用CPU时间片的百分比。例如单核CPU的时间片为6ms,有两个nice值相同,那么线程平分6ms的时间片,各占3ms。同时当线程数量很大的时候,CFS会保证每个线程获得最小的执行时间。例如单核0.75ms。

SCHED_FIFO

SCHED_FIFO和SCHED_RR是实时线程使用的调度管理算法。

SCHED_FIFO即先进先出,处于相同优先级的实时线程会根据进入运行态的次序依次执行。正在执行的线程会一直执行直到线程阻塞或者其主动调用调度线程放弃执行,处于此调度策略下的线程没有预先分配的时间片,可以永远执行下去。只有拥有更高实时优先级且处于SCHED_RR或者SCHED_FIFO管理下的线程能抢占正在运行的实时线程。

SCHED_RR

SCHED_RR在SCHED_FIFO的基础上会预先给定线程一个时间片,时间片达到后会使其他相同优先级的线程开始执行。SCHED_RR的时间片轮询机制只对同等实时优先级的线程有效,更高实时优先级的线程总是会抢占正在执行的线程,而低优先级的线程不能抢占高优先级的线程,即使其时间片已到。

实时线程优先级高于所有普通线程,如果有实时线程处于运行态,则系统调度时一定会选择调用实时线程;正在运行的实时线程只会被拥有更高实时优先级的线程抢占。所以在应用中如果需要将某个线程设置为实时线程,则需要用户自己确保该线程不会处于忙执行而完全占用CPU资源,导致其他普通线程没法获得CPU资源而一直被阻塞得不到执行,并且需要合理给予优先级的值,太高有可能会影响重要系统线程的运行。所有用户态线程默认没有实时优先级,都属于普通线程。

reference