[架构之路-39]:目标系统 - 系统软件 - Linux OS内核进程/线程调度的基本原理

Posted 文火冰糖的硅基工坊

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[架构之路-39]:目标系统 - 系统软件 - Linux OS内核进程/线程调度的基本原理相关的知识,希望对你有一定的参考价值。

目录

第1章 Linux进程概述

1.1 什么是进程

1.2 进程简单的状态迁移

1.3 进程复杂状态迁移

1.4 引起进程状态转换的具体原因如下:

1.5 进程的地址空间

1.6 用户空间如何创建进程

第2章 调度器的基本工作原理

2.1 什么是进程调度器?

2.2 为什么要调度?

2.3 为什么能调度(怎么做到能调度的)

2.4 何时调度

2.5 如何调度(调度算法)

2.6 常见的调度算法

2.7 调度优先级

2.8 多CPU的调度均衡

第3章 调度器的评价指标

第4章 调度器的发展历史

第5章 Linux进程管理命令

5.1 查看系统当前进程

5.3 终止进程

5.4 Linux服务管理

它山之石:


第1章 Linux进程概述

1.1 什么是进程

进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器程序是指令、数据及其组织形式的描述,进程是程序的实体。进程会占用四类资源:CPU,memory,disk,network

在Linux系统中,有无数个进程/线程在并发执行。 

1.2 进程简单的状态迁移

(1)运行(running)态:进程占有处理器正在运行

(2)就绪(ready)态:进程具备运行条件等待系统分配处理器以便运行。

(3)等待(wait)态:又称为阻塞(blocked)态或睡眠(sleep)态,指进程不具备运行条件,正在等待某个事件的完成。

通常,一个进程在创建后将处于就绪状态

每个进程在执行过程中,任意时刻当且仅当处于上述三种状态之一。

同时,在一个进程执行过程中,它的状态将会发生改变。

1.3 进程复杂状态迁移

进程主要有7种状态:

就绪状态、运行状态、轻度睡眠、中度睡眠、深度睡眠、僵尸状态、死亡状态,它们之间状态变迁如下:

1.4 引起进程状态转换的具体原因如下:

(1)运行态一一等待态:等待使用资源或某事件发生,如等待外设传输;等待人工干预。

(2)等待态一一就绪态:资源得到满足或某事件己经发生,如外设传输结束;人工干预完成。

(3)运行态一一就绪态:运行时间片到,或出现有更高优先权进程。

(4)就绪态一一运行态:CPU空闲时被调度选中一个就绪进程执行。

1.4 进程的切换

我们在使用电脑的时候,比如打开一个视频剪辑器,一个文本编辑器,可以认为它们都是一个进程。

假如CPU是单核的,那么在同一时间只能运行一个进程,但是给我们的感觉是视频剪辑器和文本编辑器好像是同时运行的,也就是视频剪辑器在剪辑视频的时候,我们同时可以使用文本编辑器,这是怎么实现的呢?

其实这只是我们从宏观上感觉它们是并行运行的,而微观上它们是串行运行的。也就是说,可以认为这两个进程微观上会进行频繁的切换,比如视频剪辑器运行10ms,然后文本编辑器运行10ms,如此交替,这样子它们其实串行运行的,但由于我们的反应没那么快,所以觉得它们是并行运行的,如下图所示:

一般操作系统的进程的进程数会非常的多,而一个CPU同一时间只能运行一个进程,这些进程可能是视频剪辑器,可能是文本编辑器等等。例如文本编辑器大多数时间在等待我们按下按键,并不需要占用太多CPU运行时间,而每当我们按下键盘上的按键的时候,它需要快速响应我们的操作并且将字符显示在屏幕。而视频剪辑器在剪辑视频的时候非常耗费CPU,但是它并不需要像文本编辑器那么频繁地与用户交互。也就是文本编辑器它可以占用更少地CPU运行时间,但是它需要快速响应用户操作,而视频编辑器它需要占用更多地CPU运行时间,但是它不需要快速响应用户操作,如下图所示:

1.5 进程的地址空间

 Linux 系统是一个多进程的系统,它的进程之间具有互不干扰等行性、特点。也就是说,进程之间是分离的任务,拥有各自的权利和责任。其中,每个进程都运行在各自独立的虚拟地址空间,因此,即使一个进程发生了异常,它也不会影响到系统的其他进程。

当创建一个进程,系统会分配0----4G 虚拟地址空间,其中0-----3G 是用户空间 3-----4G内核空间 。多个进程共用同一份内核, 各自进程的用户空间是独立的 。

空间的划分是由内核来决定,0—3G用户空间3—4 内核空间,这个划分是内核默认 。

1.6 用户空间如何创建进程

任何进程都是由其他的进程创建的,操作系统通过fork()、vfork()、clone()系统调用来完成进程的创建。其中Init进程称为0号进程,它是有内核启动时创建的,0号进程创建后,会启动其他初始化进程。进程创建的系统调用如下图:

第2章 调度器的基本工作原理

2.1 什么是进程调度器?

什么是调度:简单地讲,就是为进程分时复用地分配CPU资源,就是调度。

什么是调度器:调度器是CPU资源管理器。操作系统的作用之一就是管理系统资源。

CPU是计算机系统中最重要的资源,当然也要管理。所有进程的运行都需要CPU才能运行,对CPU该如何管理呢?

对于直接共享型的事物,我们有两种管理方法:

一种是空间分割管理、一种是时间分割管理,

空间分割相似性:多核CPU就是一种空间分割管理。

时间分割相似性:把一个物理的CPU分时复用分配给多个不同的进程。

进程调度:对CPU进行时间分割管理的具体做法就叫做进程调度。

那么调度的是什么呢?

进程调度,调度的当然是进程啦,也对也不对。我们知道进程是资源分配的单位,线程是执行的单位。早期的时候没有多线程,进程就是线程,线程就是进程,所以此时进程调度调度的是进程。

但是当有了多线程之后,线程变成了执行的单位,进程不再是执行的单位,而是盛放线程的容器,进程调度的就是线程了。不过由于历史原因,大家都习惯叫进程调度,所以现在这个领域的名称还是叫进程调度。后文中说到调度进程的地方都是调度的线程,由于习惯问题,我们还说调度进程不说调度线程,请大家要注意。

对线程的调度可以有两种方式:

一种是直接调度线程,不考虑它们所属的进程,这种方式叫做直接调度或者一级调度;

另一种是先调度进程,再在进程内部调度线程,这种方式叫做间接调度或者二级调度。

POSIX规定,操作系统可以选择这两种方式中的任何一种都行。

Linux选择的是一级调度,为什么会这么选择呢?主要是为了提高进程的并发性,充分利用多CPU多核的优势。如果使用二级调度的话,看似每个进程之间都公平了,但是有些进程的计算量比较大,就无法通过多开线程提高自己的性能,这样对系统整体的性能是有害的,也不利用发挥计算机多CPU的优势。一级调度看似对有些进程不公平,但是计算量小的进程少开线程,计算量大的进程多开线程,相对还是很公平的。

就像国家希望每个企业都做大做强,但是同时也会反垄断一样。Linux也推出了cgroup组调度机制,来限制某个或者某一类进程对CPU资源的过度占用。本文中不讲cgroup组调度机制,后文的讲解都是假设没有cgroup组调度。

2.2 为什么调度?

我们知道了什么是调度,那么为什么要调度呢,没有调度会怎么样呢?

要调度的根本原因是:

  • CPU Core的执行单元ALU的资源有限。
  • CPU Core的数量是有限的。
  • 需求CPU资源的进程数是“无限”,或者说远远超过CPU的资源数。

最早的计算机是没有调度的,程序只能一个一个地运行,一个进程执行完成之后才能去运行下一个进程。

这里面首先,存在的问题就是我们没法同时运行多个进程

其次就算我们不需要同时运行多个进程,程序在运行的过程中如果要等IO,CPU就只能空转,这也十分浪费CPU资源。

于是最早的多任务——协作式多任务诞生了,当程序由于要等IO而阻塞时就会去调度执行其它的进程。

但是协作式多任务存在着很大的问题,就是每个进程运行的时间片长短是不确定的,而且是很偶然很随机的。如果一个进程它一直在做运算就是不进行IO操作,那么它就会一直霸占CPU。针对这个问题,当时想出的方法是道德素养解决方案,由进程自己主动让出CPU,即内核向进程提供系统调用sched_yield,它会使进程主动放弃CPU让其它进程来执行。然后要求所有的程序员在程序中合适的地方尽量多地加入sched_yield调用。这个方法在当时是管用的,因为当时计算机的使用者(同时也是程序员)仅限于少数科研机构和政府机关的部分人员,一台电脑的共同使用者都认识,面子上还得过得去。

后来随着计算机的普及,以及计算机的使用者程序员这两个角色的分离,主要靠道德约束的协作式多任务已经行不通了,我们需要强制性多任务,也就是抢占式多任务。抢占式多任务是使用调度器使得每个进程都可以相对公平地平分CPU时间,如果一个进程运行了过长的时间就会被调度器强制性地被调度出去,不管这个进程是否愿意。有了抢占式多任务,我们在宏观上不仅可以同时运行多个进程,而且它们会一起齐头并进地往前运行,不会出现某个进程被饿死的情况,这样我们使用电脑的体验就非常完美了。抢占式多任务和协作式多任务不是对立的,它们是相互独立的,可以同时存在于系统中。于是,一个中立的、集中式的、中央集权的调度器就应运而生了。

抢占又分为用户抢占内核抢占。由于抢占对进程来说是异步的,进程被抢占时不一定运行在什么地方,有可能运行在用户空间,也有可能运行在内核空间(进程通过系统调用进入内核空间)。如果抢占点是在用户空间,那么抢占就是安全的,如果在内核空间就不一定安全,这是为什么呢?因为对于用户空间来说,如果抢占会导致线程同步问题,那么用户空间有责任使用线程同步机制来保护临界区,只要用户空间做好同步就不会出问题。如果内核也做好了同步措施,内核抢占也不会出问题,但是内核最初的设计就没有考虑内核抢占问题,所以刚开始的时候内核是不能抢占的。后来内核开发者对内核进行了完善,把内核所有的临界区都加上了同步措施,然后内核就是可抢占的了。内核能抢占了不代表内核一定会抢占,内核会不会抢占由config选项控制,可以开启也可以关闭,因为内核抢占还会影响系统的响应性和性能。开启内核抢占会提高系统的响应性但是会降低一点性能,关闭内核抢占会降低系统的响应性但是会提高一点性能。因此把内核抢占做成配置项,可以让大家灵活配置。服务器系统一般不需要与用户交互,所以会关闭内核抢占来提高性能,桌面系统会开启内核抢占来提高系统的响应性,来增加用户体验。

现在我们再来看一下为什么要调度:

因为如果没有调度的话,就不能实现多任务,一次就只能运行一个程序,我们使用电脑的体验就会大大降低。有了调度就有了多任务,我们就能同时在电脑上做很多事情,使用体验就会非常好。

2.3 为什么调度(怎么做到能调度的)

“要”调度与“能”调度是两回事,前者是原因,期望;后者是能力。

我们再来看看为什么能调度呢。我们把协作式多任务叫做进程自己主动调度,抢占式多任务叫做进程被动调度。

为什么能调度分为两部分:为什么能触发调度和为什么能执行调度。

对于主动调度,调度是进程主动触发的,这个是肯定能的,进程自己主动让出CPU。

对于被动调度,在图灵机模型中是做不到的,因为图灵机是一条线性一直往前走的,进程在执行时,进程要是不主动,是不可能跳到其它进程来执行的。被动调度能做到的原因关键就在于中断机制,因为中断是强行在正常的执行流中插入了一段代码,它能改变后续代码的走向。有了中断机制,我们就可以创建一个定时器中断,以固定的时间间隔,比如每10ms来触发中断,然后执行调度器的算法检测进程是否运行时间过长,如果过长就触发调度。这样任何进程都不可能霸占CPU,所以进程都能公平地共享CPU时间。这里引用其中的一幅图来看一下:

可以看到在纯图灵机模型中,进程如果不主动进行调度,是没有外力强迫进程进行调度的,进程就能一直霸占CPU。

有了中断机制之后,在中断的处理中可以触发调度,在中断返回的点可以执行调度,这样就可以避免进程霸占CPU了。

前面说的是为何能触发进程调度,主动调度是进程自己触发的,被动调度是在中断中触发的。

现在来看看为何进行调度,执行调度包括两部分:

选择进程和切换进程。

选择进程是纯软件的,肯定能实现。

切换进程是怎么切换呢?一个进程执行的好好的,怎么就切换了呢,需不需要硬件的支持呢?进程切换主要是切换执行栈用户空间,这两个都需要用到CPU特定的指令。

2.4 何时调度

我们前面已经讲了主动调度(协作式多任务)和被动调度(抢占式多任务)。

对于主动调度,触发调度和执行调度是同步的、一体的,触发即执行。主动调度发生的时机有IO等待、加锁失败等各种阻塞操作以及用户空间主动调用sched_yield。

对于被动调度,触发调度执行调度是异步的、分离的,触发调度并不会立马执行调度,而是做个需要调度的标记,然后在之后的某个合适的地方会检测这个标记,如果被设置就进行调度。

(1)触发调度的时机点有:

  1. 在定时器中断中发现当前进程超时了,
  2. 在唤醒进程时发现新进程需要抢占当前进程,
  3. 在迁移进程时发现新进程需要抢占当前进程,
  4. 在改变进程优先级时发现新进程需要抢占当前进程。

其中第一个触发点是当前进程需要被抢占,它是用来保证公平调度,防止进程霸占CPU的,

后三个触发点是新进程需要抢占当前进程,它是用来提高系统响应性的。

(2)执行调度的时机点有:

  • 系统调用完成之后即将返回用户空间,
  • 中断完成之后即将返回用户空间
  • 如果开启了内核抢占的话则还有,中断完成之后即将返回内核,
  • 如果中断发生在禁止抢占临界区中,那么中断完成之后返回内核是不会执行调度的,而是会在临界区结束的时候执行调度。

下面的几个图来看一下这几个执行调度检测点:

 同一时刻,CPU只能执行如下程序中的一个:

  • 中断程序
  • 内核空间程序
  • 用户空间程序

  • 系统调用完成之后即将返回用户空间
  • 中断完成之后即将返回用户空间
  • CPU异常处理后返回用户空间

是非常好的执行进行调度的点,也就是此图中的三个箭头的地方。

CPU异常在意义上不是系统调用,但是在形式上和逻辑上相当于是系统调用。

用户进程 -》 系统调用 -》 内核程序 -》 CPU异常处理 -》内核进程 -》 用户进程 

用户进程 -》 系统调用 -》 内核程序 -》 中断服务处理 -》 内核进程 -》 用户进程 

 用户进程 -》 系统调用 -》 内核程序 -》 CPU异常处理 -》中断服务 -》CPU异常处理 -》 内核进程 -》 用户进程 

中断发生在内核空间的场景,如果开启了内核抢占,如果被抢占的内核代码不是在禁用抢占临界区,中断返回时是执行调度的点。如果被抢占的内核代码在禁用抢占临界区中,在执行调度的点被推迟到了临界区的出口处。

2.5 如何调度(调度算法)

现在到了执行调度的时刻了。

执行调度分为两步:一是选择下一个要执行的进程,二是切换进程。

(1)选择下一个要执行的进程

选择下一个要执行的进程,这就是调度算法了。

首先,调度算法只能从Runnable的进程中进行选择,不能选择Blocked进程,因为选择了也没有意义。

其次,算法还要区分进程类型,比如普通进程与实时进程,肯定要优先选择实时进程,在同一类型的进程中还要有具体的算法来决定到底选择哪个进程。

在Linux中一共把进程分为了5类,每一类都有一个具体的算法。

类之间的关系是选择优先高的进程,只有当优先级高的类没有Runnable进程时才会去选择低类进程。

(2)切换进程

进程选择好了之后就要切换进程了。

切换进程分两步:

第一步是切换用户空间,第二步是切换执行栈(线程栈)。

如果要切换的两个线程属于同一个进程就不需要切换用户空间了。

切换用户空间是一个CPU架构相关的事情,在x86 CPU上是给CR3寄存器赋值新进程的页表树的根指针。此时切换的执行栈是线程的内核栈执行栈代表的是当前线程的执行情况,切换执行栈就是切换线程。线程的用户栈信息都在内核栈里保存着。

 切换完内核栈之后,线程继续执行就会返回用户空间,由于此时用户空间已经切换完成,内核栈上也保存着用户栈的信息,所以线程能返回到正确的用户空间线程上去。

下面我们画个图来看一下:

对于一个CPU来说,永远只有一个当前进程在运行,当执行进程调度时,需要从其它进程中选择一个进程,把它旋转到最下方作为当前进程,它就开始运行了。

2.6 常见的调度算法

内核中有调度类、调度策略、调度算法的概念,这三者是什么意思,又有什么关系呢?

调度类代表的是进程对调度器的需求,主要是对调度紧迫性的需求。

调度策略是调度类的子类,是对调度类的细分,是在同一个调度需求下的细微区别。

调度算法是对调度类的实现,一个调度类一个调度算法。

同一个调度类的调度策略是有很强的相似性的,所以在同一个算法中实现,对于它们不同的部分,算法再去进行区分。

下面我们画个图来看一下Linux中的所有调度类、调度策略和调度算法。

2.7 调度优先级

(1)用户空间进程

用户空间的时候,实时进程普通进程(分时进程)共享同一个优先级数轴,叫静态优先级,范围是0-99,值越大优先级越高

实时进程占用1-99,普通进程占用0

普通进程自己又新开了一个数轴,叫动态优先级,也叫nice值,范围是 -20 - 19,值越低优先级越高。

(2)内核空间进程

到了内核空间的时候,

实时进程有一个实时优先级,直接复制了用户空的静态优先级,

普通进程有一个静态优先级,它是用户空间的nice值转换过来的,转换规则是nice+120。然后内核又定义了规范优先级,把它们都统一到同一个数轴上来。

普通进程的规范优先级是直接复制其静态优先级,实时进程的规范优先级等于99减去它的实时优先级。

在规范优先级的数轴上,所有进程都可以直接比较优先级了,值越小优先级越大

实时进程的规范优先级范围是0-99,但是由于它是从用户空间的优先级计算而来的,所以99这个值就用不到。

最后是动态优先级,对进程所有的处理都以动态优先级为准,动态优先级默认等于其规范优先级。以前的时候调度算法会去调整进程的动态优先级,现在不会再调了。现在只有使用了优先级继承锁的时候才会去调整进程的动态优先级。

下面让我们再画一个图总结一下:

2.8 多CPU的调度均衡

前面所说的都是针对一个CPU的情况,对于多个CPU来说,每个CPU也是这样的逻辑。

但是有一点不同的是,如果一个系统上的多个CPU忙的忙死,闲的闲死,显然不太好,因此多个CPU之间会进行调度均衡

调度均衡可以分为个体均衡和总体均衡。

个体均衡是从进程的角度出发选择到一个相对清闲的CPU上去运行。

个体均衡的触发点有三个:

  • 一是新进程刚创建时,
  • 二是进程要执行新程序时,
  • 三是进程被唤醒时,在这三个点进程都可以选择去哪个CPU的运行队列上去等待执行。

在个体均衡下,每个进程都尽量选择相对清闲的CPU,所以所有CPU的负载应该还是会比较均衡的。

但是时间长了可能还是会出现负载不均衡的情况,此时就要进行总体均衡了。

总体均衡是从CPU的角度出发如何从别的CPU上拉取一些进程到自己这来执行,使得所有CPU的工作量尽量平均。

总体均衡的触发点有三个:

  • 一是CPU即将idle前会去找到最忙的CPU然后拉取一些任务过来;
  • 二是定时器中断的周期性检测,会检查是否所有的CPU都一样忙,如果忙闲差别太大就会进行进程迁移,使得所有CPU忙闲程度接近;
  • 三是在idle进程中如果CPU发现自己太忙,而有的CPU在idle就会唤醒那个CPU进行负载均衡。

第3章 调度器的评价指标

狭义的调度器指的是具体的调度算法,

广义的调度器指的是整个调度体系。

不过两者的评价指标是相同的,所以我们这里不具体区分调度器是指调度算法还是调度体系。

调度器的评价指标有以下几个:

(1)响应性

响应性是指,当一个进程发生事件需要去处理的时候能否及时被调度。

这一点和使用体验是密切相关的,当我们用鼠标点击一个程序的时候,肯定希望程序立即能做出响应,如果程序过了好几秒才有反应,那我们肯定会很烦的。

(2)有效吞吐量

吞吐量是指系统在相同的时间内能够运行更多的程序、执行更多的指令。

  • 调度器的效率

这个首先要求调度器本身的代码要尽量的高效。如果调度器写得非常复杂,运行一次就需要好几毫秒的话,那留给进程运行的时间就不多了。

  • 调度的频率

其次进程调度的频率要低,如果进程调度的频率比较高的话,那调度器执行的次数就比较多,从而占用了较多的CPU时间,而且频繁切换进程也会影响缓存的性能。

从这一点来看响应性有效吞吐量是有矛盾的,提高响应性会增加进程切换的频率,而这会降低系统的吞吐量。

(3)公平性

公平性指的是相对公平性,每个进程实际获得的时间份额与应当获得的时间份额都相差不大。不会出现有些进程饥饿的情况,也不会出现有些进程获得过多时间份额的情况。

(4)适应性

指的是系统无论是调度几个进程还是调度几万个进程,都能撑得住,都能收放自如,各项指标都不能受到太大的影响。

(5)节能性

自从智能手机越来越普及,而手机的电池技术一直没有较大的突破,所以省电对手机来说就是一项非常重要的任务,调度器也不可避免地要考虑省电问题了。

第4章 调度器的发展历史

Linux的调度器经历了长久的发展,是内核中被优化最多目前最完善的模块之一。下面我们来看一下Linux调度器发展的历史。

Traditional Scheduler: v1.0 – v2.4

这一阶段的调度器和传统的UNIX上的调度器逻辑是一样的。全局只有一个运行队列,所有进程都放在一个队列上。进程区分IO密集型和CPU密集型,根据进程的睡眠时间计算动态优先级,按照动态优先级决定进程的调度顺序,按照优先级分配进程的时间片大小,时间片大小是等差数列。进程在运行队列上并没有特定的排序,每次选择下一个进程的时候都要遍历整个队列,所以算法的时间复杂度是O(n)。在SMP上也只有一个运行队列,当CPU比较多进程也比较多的时候,锁冲突比较严重。

O(1) Scheduler: v2.5 – v2.6.22

此调度器主要是针对传统调度器进行了改进。首先把运行队列从单一变量变成了per-CPU变量,每个CPU一个运行队列,这样就不会有锁冲突了,不过这样就需要调度均衡了。其次把运行队列的一个链表分成了两个链表数组:活动数组和过期数组。时间片没用耗尽的进程放在活动数组中,时间片耗尽的进程放在过期数组中,当所有进程的时间片都耗尽的时候交换两个数组,重新分配时间片。两个数组都使用动态优先级排序,并用bitmap来表示哪个优先级队列中有可运行的进程,把选择进程的算法复杂度降低到了O(1)。对进程区分IO密集型和CPU密集型并计算动态优先级这一点和传统调度器一样没有变。

SD Scheduler:(未合入)

楼梯调度器,它是对O(1)调度器的改进,算法复杂还是O(1)。之前的调度器都区分IO密集型和CPU密集型,算法要对进程的类型进行探测,根据探测结果调整动态优先级。这就有很大的问题,探测不一定准确,而且进程还可以欺骗调度器,最终会导致调度有很大的不公平性。楼梯调度器是第一次尝试使用公平调度算法,它废除了动态优先级,不再区分IO密集型进程和CPU密集型进程,但是仍然让IO密集型进程保持较高的响应性。在实现上,楼梯调度算法废弃了过期数组,只使用一个数组。当进程使用完自己的时间片之后,其时间片就会被减半并下降到下一个优先级,其本身的优先级还是不变的。当进程下降到最后一个优先级之后就再回到它本来的优先级队列并重新分配时间片。整个过程就像下楼梯一样,所以这个算法就叫做楼梯调度器。此算法虽然没有合入到标准内核,但是它第一次证明了可以采取完全公平的思想进行调度,也就是不区分IO密集型和CPU密集型进程。

RSDL Scheduler:(未合入)

旋转楼梯调度器,是对楼梯调度器的改进。又重新引入了过期数组,为每个优先级都分配一个组时间配额记为Tg,进程本身的时间片记为Tp。当进程用完自己的时间片时会下降一个优先级,当一个优先级的Tg被用完时,组内所有的进程都会下降一个优先级。进程下降到最低优先级之后会被放入过期数组,当活动数组为空时就会交换活动数组和过期数组。由于加了Tg,使得低优先级进程的调度延迟可控,进一步增加了公平性。

CFS: Completely Fair Scheduler: v2.6.23 – now

完全公平调度器,从SD/RSDL中吸取了完全公平的思想,不再区分IO密集型进程与CPU密集型进程,不再根据睡眠时间调整动态优先级,所有普通进程都按优先级相对平分CPU时间,算法复杂度是O(logn)。此时对调度器框架也进行了重构,和之前的有很大的不同。之前的调度器是一个算法调度所有进程,在算法内部区别对待实时进程和普通进程。现在的调度器框架是先区分不同类型的进程,普通进程一个调度类,实时进程一个调度类,调度类里面再去实现具体的调度算法。CFS是普通调度类的算法。

第5章 Linux进程管理命令

进程管理命令的用途:(1)判断系统的健康状态 (2)查看系统的所有进程(3)结束相应进程

5.1 查看系统当前进程

(1) ps命令

ps aux(查看当前时间节点进程信息)

ps aux | grep zx ( 表示查找zx用户使用的进程,)

 ps le \\ps ef(l表示显示详细信息,e表示显示所有进程)

USER:该进程是由那个用户产生的

PID:进程的ID编号

%CPU:该进程的CPU资源占用百分比

%MEM:该进程的内存资源占用百分比

VSZ:该进程的虚拟内存的大小,单位KB(将磁盘的一部分空间转为虚拟内存使用,在物理内存使用占满后才会用到)

RSS:该进程占用实际物理内存的大小,单位KB

TTY:该进程是在哪个终端上运行的(TTY1~TTY6代表本地控制台终端。TTY1是图形终端,TTY2~6是本地的字符界面终端。PTS/0-255代表虚拟终端。)

STAT:进程状态。R:运行、S:睡眠、T:停止、s:包含子进程、+:位于后台

START:该进程启动时间

TIME:该进程占用系统得到运算时间(注意不是系统时间)

COMMAND:产生此进程的命令名

(2)top命令

top (表示进入监听模式,输入h显示帮助,输入P以cpu进行排序,M以内存排序,N以PID排序,输入q可以退出,该命令可以动态显示进程的信息变化)

        第一行是系统信息:    

 16:34:25 是系统时间;Up1day,14:17是系统运行时间;1 user是系统当前登录用户数量;

      load average:0.00,0.00,0.00是系统1分钟5分钟15分钟内的平均负载。大于1表示超负载

        第二行是进程信息:

Tasks:290total表示系统进程总数;running表示正在运行的进行;sleeping表示睡眠的进程

stopped便是已停止的进程;zombie表示僵尸进程(如果不是0,需要手动检查)

        第三行是cpu信息:

us表示用户占用cpu百分比;sy表示系统占用cpu百分比;ni表示改变过优先级的用户占用百分比

id表示空闲cpu占用百分比;wa表示等待输入/输出的进程占用百分比;hi表示硬件中断请求服务占用百分比;si表示软件中断请求服务占用百分比;st表示steal time虚拟时间百分比,就是当有虚拟机时虚拟cpu等待实体cpu的时间百分比

        第四行是物理内存信息:

Mem表示物理内存总量;used表示以使用的物理内存;free表示闲置物理内存;buffers表示缓冲数量

        第五行是交换分区(swap)信息:

swap表示交换分区(虚拟内存)的在大小;used表示已经使用的交互分区的大小;free表示空闲交换分区的大小;cached表示作为缓存的交换分区大小

pstree(查看进程树,可以直观的看出父进程与子进程的关系)
pstree -p(将进程树全部展开,查看到对应的PID)

(3)pstree(查看进程树,可以直观的看出父进程与子进程的关系)

pstree -p(将进程树全部展开,查看到对应的PID)

5.3 终止进程

1, SIGHUP, 该信号让进程⽴即关闭,然后重新读取配置⽂件之后重启

2 ,SIGINT ,程序终⽌信号,⽤户终⽌前台进程。相当去输出ctrl+c快捷键

9, SIGKILL, ⽤来⽴即结束程序的运⾏,本信号不能被阻塞、忽略。⼀般 ⽤于强制终⽌进程

使用 kill命令终止进程

18, SIGCONT, 信号可以让暂停的进程恢复执⾏,本信号不能被阻断

19, SIGSTOP ,该信号可以暂停前台进程,相当于输⼊crtl+z快捷键。本信号 不能被阻断

kill -1 32411   (重启PID为32411的进程)

kill -9 32425(强制终⽌PID为32425的进程)

kill -15 32452(相当于kill 32452,正常结束PID为32452的进程)

5.4 Linux服务管理

服务就是进程,进程不一定是服务。

服务是具备一定功能的进程,但有些进程并不具备服务的特征

linux中的第一个进程,就是整个系统的父进程。负责了后面所有的其他进程的启动。

在RHEL6版本之前采用的第一个进程为init,但通过init进程启动的后续进程都是串行启动的,串行启动就意味着速度慢。每个进程需要排队一个一个启动

在RHEL7版本至今,采用的第一个进程为systemd。该进程相比init来说,采用了并行启动的方式,并行启动就意味着速度更快。

systemd管理的内容不仅仅有service,systemd管理的单位是unit,service只是unit(单位)中的一种。

systemctl list-units (查看systemd管理的信息)systemctl list-unit-files (查看)

(1)systemd管理服务(service)操作

systemctl status NetworkManager.service(查看NetworkManager服务的信息)

systemctl stop NetworkMannger(停止NetworkMannger服务)

systemctl start NetworkMannger(启动NetworkMannger服务) 

systemctl restart NetworkMannger(重新启动NetworkMannger服务)

(2)systemd管理target

target是由服务组成的一组启动目标。systemd可以设置启动目标,如果指定了一个target作为启动目标,那么下次系统启动时就会启动target里面的所有服务。

systemctl get-default (该命令表示显示下一次启动哪一个target)

(3)multi-user.target (包含了字符界面组件的linux系统)

systemctl isolate multi-user.target (该命令表示临时将系统界面切换到字符界面 )

systemctl set-default multi-user.target (表示下一次开机启动将系统界面切换到字符界面 )

(4)graphical.target (包含了图形界面组件的linux系统)

systemctl isolate graphical.target (该命令表示临时将系统界面切换到图形界面 )

systemctl set-default graphical.target (表示下一次开机启动将系统界面切换到图形界面 )
 

它山之石:

六万字 | 深入理解Linux进程调度_布道师Peter的原理博客-CSDN博客

以上是关于[架构之路-39]:目标系统 - 系统软件 - Linux OS内核进程/线程调度的基本原理的主要内容,如果未能解决你的问题,请参考以下文章

[架构之路-11]:目标系统 - 架构 - 嵌入式系统软件+硬件的基本通用架构

[架构之路-56]:目标系统 - 平台软件 - 总体架构概述

[架构之路-28]:目标系统 - 系统软件 - Linux OS内核功能架构图解内核构建内核启动流程

[架构之路-25]:目标系统 - 系统软件 - bootloader uboot内存映射与启动流程

[架构之路-21]:目标系统 - 系统软件 - 计算机系统架构计算机指令系统结构化程序与分层编程。

[架构之路-29]:目标系统 - 系统软件 - Linux OS内核以及内核驱动的调试技术