第7章 进程调度

 

1 Linux进程简介

  • Linux中,进程的优先级是动态的
  • Linux 2.6开始,内核是抢占式的
  • 内核线程没有自己的地址空间,整个内核共享内核的虚拟地址
  • Linux采用对称多处理模型,每个CPU地位相同

 

 

2 进程分类

进程可以分为普通进程(包括交互式进程、批处理进程)、实时进程。

交互式进程和实时进程的区别是:

交互式进程是用于用户交互的进程,需要控制响应时间较短而且不能波动—— 不能太短也不能太长;

实时进程需要最高进程优先级和最短的响应时间。

 

 

3 普通进程的调度

3.1 静态优先级

内核用100~139表示普通进程的静态优先级,值越大静态优先级越小

静态优先级和nice成正相关,100~130分别对应nice值的-20~19

静态优先级通过影响进程时间片来影响进程执行的“优先级” —— Linux进程基于时间片调度

父进程生成新进程的时候,会把自己的时间片也分一半给子进程;子进程执行完如果时间片没有用完时间片,会返回给父进程

 

3.2 动态优先级

动态优先级在调度程序选择执行进程的时候使用

静态优先级(正相关) && 平均睡眠时间(负相关,确定交互式进程/批处理进程) => 动态优先级

 

3.3 活动进程和过期进程

活动进程:时间片还没用完,应该是被抢占的进程

过期进程:时间片被用完,因为没有被阻塞,所以肯定还是TASK_RUNNING状态,只不过执行完后放在过期进程链表最后了

用完时间片的活动批处理进程总是变成过期进程,而用完时间片的活动交互式进程,会被重新填时间片并仍旧是活动进程!

(交互式进程占用CPU处理量很小,所以优先级很高也没有问题)

运行进程结构体runqueue里面有包括活动进程和过期进程的两个链表:prio_array_t [2] arrays

因为活动进程和过期进程会进行交换,所以需要有两个链表指针来进行操作:prio_array_t *active; prio_array_t *expired

 

 

4 实时进程的调度 

4.1 实时进程简介

实时进程有一个实时优先级,调度程序总是让实时优先级高的进程执行;

和交互式进程一样,实时进程也总是活动进程;

 

4.2 实时进程被取代的情况

  • 实时进程被另一个更高优先级的实时进程取代
  • 进程本身执行了阻塞操作并休眠,或者执行力sche_yield()主动让出CPU
  • 进程停止或被杀死

普通进程基于时间片执行,实时进程基于优先级调度。

 

 

5 调度程序使用的函数

5.1 实时进程scheduler_tick()

① 每次时钟节拍到来时都会调用 —— 应该指的是Linux的1ms周期的时钟节拍

② 如果当前进程是FIFO,什么都不做;如果是基于时间片的调度策略,往下走

③ 首先递减时间片计数器,并检查是否已经用完时间片 —— 如果用完,就进行进程调度

  • 重填进程的时间片
  • 设置RIF_NEED_RESCHED标志,准备进程调度
  • 把当前进程描述符从当前活动链表头移到当前活动链表的尾部

 

5.2 普通进程scheduler_tick()

和实时进程的调度步骤基本一致,差别在于最后不是把进程从链表头移到链表尾,而是:

把当前进程插入活动进程集合(交互式进程,执行完时间片仍旧是活动进程)或者过期进程(批处理进程,执行完就过期)。

 

 

5.3 try_to_wake_up()

① 禁用本地中断

② 为当前进程寻找合适的CPU及其runqueue

  • 如果系统中某些CPU空闲,就选择空闲CPU的rq作为目标
  • 如果该进程所属的CPU的工作量远小于本地CPU的工作量,就选择该进程所属CPU的rq
  • 如果进程最近被执行过,就选择老的运行队列作为目标

③ 把进程state设置为TASK_RUNNING

④ 打开本地中断并返回

 

5.4 recalc_task_prio()

更新进程的平均睡眠时间和动态优先级

 

5.5 schedule()

当前进程被阻塞时调用schedule();

① 直接调用

  • 把current插入适当的等待队列
  • 把current进程状态改为TASK_INTERRUPTIBLE或TASK_UNINTERRUPTIBLE
  • 调用schedule()
  • 多次检查资源是否可用,不可用回到2,可用就从等待队列删除当前进程

② 延迟调用

如果把TIF_NEED_RESCHED置位,就会在每次检查TIF_NEED_RESCHED的时候触发进程调度;

③ 步骤

  • 禁用内核抢占,关闭本地中断,获取自旋锁
  • 从可运行队列中获取next进程
  • 进行进程切换:加载next进程,开始运行next

 

 

6 与调度相关的系统调用

nice():降低当前进程的优先级(对其它进程很nice);已被setpriority()取代

getpriority():返回 20 - 给定中所有进程中最低nice值

setpriority():把给定中所有的进程的基本优先级都设置为一个给定的值

sched_getscheduler():查询由pid参数所表示的当前进程所用的调度策略,包括SCHED_FIFO,SCHED_RR,SCHED_NORMAL;

sched_setscheduler():设置调度策略

sched_yield():进程自愿放弃CPU,但是仍保持TASK_RUNNING状态;

如果是普通进程,调度程序把它放到运行队列的过期进程集合中;

如果是实时进程,调度程序把它放到运行队列链表的末尾

 

posted @   moonのsun  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示