文章目录
- 1 进程
- 1.1 进程的概念、组成与特征
- 1.2 进程的状态与转换
- 1.3 进程的组织
- 1.4 进程控制
- 1.5 进程通信
- 2 线程与多线程模型
- 2.1 线程的概念
- 2.2 线程的实现方式
- 2.3 多线程模型
- 2.4 线程的状态与转换
- 3 处理机调度
- 3.1 调度的三个层次
- 3.2 进程的挂起态与七状态模型
- 3.3 进程调度
- 3.3.1 进程调度的时机
- 3.3.2 进程的调度方式
- 4 调度算法(重点!!!)
- 4.1 调度算法的评价指标
- 4.2 适用于批处理系统的调度算法
- 4.2.1 先来先服务(FCFS)
- 4.2.2 短作业优先(SJF)
- 4.2.3 高响应比优先(HRRN)
- 4.3 适用于交互式系统的调度算法
- 4.3.1 时间片轮转(RR)
- 4.3.2 优先级调度算法
- 4.3.3 多级反馈队列调度算法(后续补充)
1 进程
1.1 进程的概念、组成与特征
程序: 是 静态的, 是存放在磁盘里的可执行文件,是一系列的指令集合。
进程(Process): 是 动态的, 是程序的一次执行过程。进程是进程实体的运行过程,是系统进行资源分配和调度的一个独立单位。
示例:QQ程序仅一个,但是可以同时打开多个QQ,进程就多出来了几条。即,同一个程序多次执行会对应多个进程。
❓ 思考: 操作系统是这些进程的管理者,它要怎么区分各个进程呢?
答:当进程被创建时,操作系统会为该进程分配一个唯一的、不重复的“身份证号”——PID(Process ID,进程ID)。
进程的组成
一个进程的实体(进程映像)有PCB、程序段、数据段组成。
进程是动态的,进程实体(进程映像)是静态的。进程实体反应了进程在某一时刻的状态。
进程控制块(PCB)—— 进程存在的唯一标志!
操作系统要记录PID、进程所属用户ID(UID),还要记录给进程分配了哪些资源(如:分配了多少内存、正在使用哪些I/O设备、正在使用哪些文件),还要记录进程的运行情况(如:CPU的使用时间、磁盘的使用情况、网络流量使用情况等)。
以上信息都被保存在一个数据结构PCB(Process Control Block)中,即进程控制块。
操作系统对进程进行管理工作所需的信息都存在PCB中,PCB是进程存在的唯一标志,当进程被创建时,操作系统为其创建PCB,当进程结束时,会回收其PCB。
通过程序运行过程来理解进程的组成:
一个程序开始运行前,程序需要从硬盘读入内存 。在运行前,需要创建对应的进程,同时创建对应的进程控制块,也就是PCB。然后,CPU会读取一系列指令,我们把这些程序指令称为程序段。而在,执行程序段的过程中,会产生一些数据,这些数据我们称作数据段。
进程的特征
程序是静态的,进程是动态的,相比于程序,进程拥有如下特征:
- 动态性: 动态性是进程最基本的特征。 进程是程序的一次执行过程,是动态地产生、变化和消亡的。
- 并发性: 内存中有多个进程实体,各进程可以并发执行。
- 独立性: 进程是能够独立运行,独立获得资源,独立接收调度的基本单位。
- 异步性: 各进程按各自独立的、不可预知的速度向前推进,操作系统要提供“进程同步机制”来解决异步问题。
- 结构性: 每个进程都会配置一个PCB。从结构上看,进程由程序段、数据段和PCB组成。
1.2 进程的状态与转换
进程的状态
创建态、就绪态
进程正在被创建时,它的状态是 “创建态”, 在这个阶段操作系统会为进程分配资源、初始化PCB。
当线程创建完成后,便会进入 “就绪态”, 处于就绪态的进程已经具备运行条件,但由于没有空闲CPU,则暂时不能运行。
运行态
当CPU空闲时,操作系统就会选择一个就绪进程,让它上处理机运行。如果一个进程此时在CPU上运行,那么这个进程就处于 “运行态”, CPU会执行该进程对应的程序(执行指令序列)。系统中可能会有很多个进程都处于就绪态。
阻塞态
在进程运行的过程中,可能会请求等待某个事件的发生(比如,等待某种系统资源的分配,或者等待其他进程的相应)。
在这个事件发生之前,进程无法继续向下执行,此时操作系统会让这个进程下CPU,并让它进入 “阻塞态”。
终止态
一个进程可以执行 exit 系统调用,请求操作系统终止该进程。此时该进程会进入 “终止态”, 操作系统会让该进程下CPU,并回收内存空间等资源,最后还要回收该进程的PCB。
进程状态的转换
如图所示:
进程的整个生命周期中,大部分时间都处于三种基本状态:运行态、就绪态、阻塞态。单CPU情况下,同一时刻只会有一个进程处于运行态,多核CPU情况下,可能有多个进程处于运行态。
进程PCB中,会有变量state来表示进程的当前状态。如:1表示创建态、2表示就绪态、3表示运行态… …
1.3 进程的组织
链接方式与索引方式
1.4 进程控制
进程控制的主要功能是对系统中的所有进程实施有效的管理,它具有创建新进程、撤销已有进程、实现进程状态转换等功能。
简而言之,进程的控制就是要实现进程状态的转换。
如何实现进程控制?
进程控制用 “原语” 实现。原语的执行具有 “原子性”,一气呵成。
那么为什么进程的控制需要一气呵成呢?
Eg 假设PCB中的变量State表示进程当前所处状态,1表示就绪态,2表示阻塞态… … 如下图所示:
假设此时进程2等待的事件发生,则操作系统中,负责进程控制的内核程序至少需要完成以下的操作:
- 将PCB2的state设置为1;
- 将PCB2从阻塞队列放到就绪队列。
如果说,完成了第一步后,收到了中断信号,那么此时就会发生 PCB2 的state = 1,为就绪态,但是它却被放在了阻塞队列里。
所以说,如果不能一气呵成,就有可能导致操作系统中某些关键结构信息不统一的情况,这会影响操作系统进行别的管理工作。
如何实现原语的“原子性”?
原语的执行具有原子性,即执行过程只能一气呵成,期间不允许被打断。可以用 “关中断指令” 和 “开中断指令” 这两个特权指令实现原子性。
在正常情况下,CPU每执行完一条指令都会例行检查是否有中断信号需要处理,如果有,则暂停运行当前这段程序,转而执行相应的中断处理程序。
CPU执行了关中断指令后,就不再例行检查中断信号,直到执行开中断指令之后,才会恢复检查。
这样,关中断、开中断 之间的这些指令序列就是不可被中断的,这就实现了 “原子性”。
进程控制相关的原语
创建原语
撤销原语
阻塞原语与唤醒原语
因为何事阻塞,就应该由何事唤醒。所以,阻塞原语和唤醒原语是成对使用的。
切换原语
切换原语实现 运行态 与 就绪态 的相互切换。
在进程的切换时一般现在PCB中保存这个进程的运行环境(保存一些必要的寄存器信息),当原来的进程再次投入运行时,可以通过PCB恢复它的运行环境。
1.5 进程通信
什么是进程间通信?
进程间通信(Inter-Process Communication, IPC)是指两个进程间产生数据交互。
为什么进程通信需要操作系统的支持?
进程是分配系统资源的单位(包括内存地址空间),因此各进程拥有的内存地址空间相互独立。 出于安全考虑,各个进程只能访问自己进程的地址空间,而不能访问其他进程的地址空间。即:一个进程不能直接访问另一个进程的地址空间。
进程通信的三种方式
共享存储
基于存储区的共享: 操作系统在内存中划出一块共享存储区,数据的形式、存放位置都由通信进程控制,而不是操作系统。这种共享方式速度很快,是一种高级通信方式。
进程P和进程Q想要通信,可以申请一片共享内存区。这样通过对共享内存区的访问,就能实现P、Q进程的通信了。
但是多个进程如果都在共享存储区写数据,就有可能造成写冲突,发生数据覆盖的问题。
为了避免出错,各个进程对共享空间的访问应该是互斥的。
基于数据结构的共享: 比如共享空间里只能放一个长度为10的数组。这种共享方式速度慢、限制多,是一种低级通信方式。
消息传递
进程间的数据交换以格式化的消息为单位。进程通过操作系统提供的 “发送消息/接收消息”两个原语进行数据交换。
直接通信方式:
点名道姓的消息传递。进程A通过发送原语,编辑好消息头和消息体,指名发给谁。然后操作系统内核中进程Q的PCB接收存储到消息队列。而后Q进程通过接收原语,查找消息队列中由P进程发送的消息,完成接收。
间接通信方式:
以信箱作为中间实体进行消息传递。可以多个进程往同一个信箱发送消息,也可以多个进程从同一个信箱中接收消息。
管道通信
数据的流向只能是单向的(不能同时进行,在某一时刻是单向的)。一端写数据,另一端读数据。先进先出。
这里所说的管道,是一种特殊的共享文件,又名pipe文件。其实就是在内存中开辟一个大小固定的内存缓冲区。
共享存储的通信方式相较管道通信更加自由,因为共享存储的方式存储方式不受限,相对自由,而管道通信的缓存区则更像是一个循环队列。
- 管道只能采用半双工通信, 某一时间段内只能实现单向的传输。如果要实现 双向同时通信, 则 需要设置两个管道。
- 各进程要互斥地访问管道(由操作系统实现)。
- 当管道写满时,写进程将阻塞, 直到读进程将管道中的数据取走,即可唤醒写进程。
- 当管道读空时,读进程将阻塞, 直到写进程往管道写入数据,即可唤醒读进程。
- 管道中的数据一旦被读出,就彻底消失。因此,当多个进程读同一个管道时,可能会发生错乱。对此,通常有两种解决方案:(1)一个管道允许多个写进程,一个读进程;(2)允许有多个写进程,多个读进程,但系统会让各个读进程轮流从管道中读数据。
2 线程与多线程模型
2.1 线程的概念
线程可以理解为轻量级进程。
线程是一个基本的CPU执行单元,也是程序执行流的最小单位。
为什么要引入线程呢?
引入线程之后,不仅是进程之间可以并发,进程内的各线程之间也可以并发,从而进一步提升了系统的并发度,使得一个进程内也可以并发处理各种任务(如QQ视频、文字聊天、传文件)。
引入线程后带来的变化如下:
线程的属性如下:
- 线程是处理机调度的单位
- 多CPU计算机中,各个线程可占用不同的CPU
- 每个线程都有一个线程ID、线程控制块 (TCB)
- 线程也有就绪、阻塞、运行三种基本状态
- 线程几乎不拥有系统资源
- 同一进程的不同线程间共享进程的资源
- 由于共享内存地址空间,同一进程中的线程间通信甚至无需系统干预
- 同一进程中的线程切换,不会引起进程切换
- 不同进程中的线程切换,会引起进程切换
- 切换同进程内的线程,系统开销很小;而切换进程,系统开销较大
2.2 线程的实现方式
1.用户级线程
在早期的操作系统中,比如Unix,只支持进程,不支持线程。当时的"线程"是通过线程库实现的。
1.用户级线程由应用程序通过线程库实现,所有的线程管理工作都由应用程序负责(包括线程切换)
2.用户级线程中,线程切换可以在用户态下即可完成,无需操作系统干预。
3. 在用户看来,是有多个线程。但是在操作系统内核看来,并意识不到线程的存在。“用户级线程”就是“从用户视角看能看到的线程”
优点: 用户级线程线程切换在用户空间即可完成,不需要切换核心态,线程管理开销小,效率高。
缺点: 当一个用户级线程被阻塞后,整个进程都会被阻塞,并发度不高。
2.内核级线程
内核级线程是内核支持的线程,由操作系统支持。
1.内核级线程的管理工作由操作系统内核完成。
2.线程调度、切换等工作都由内核负责,因此内核级线程的切换必然需要在核心态下才能完成。
3. 操作系统会为每个内核级线程建立相应的TCB (Thread Control Block,线程控制块),通过TCB对线程进行管理。“内核级线程”就是“从操作系统内核视角看能看到的线程”
优点: 当一个线程被阻塞后,别的线程还可以继续执行,并发能力强。 多线程可在多核处理机并行执行。
缺点: 一个用户进程会占用多个内核级线程,线程切换由操作系统内核完成,需要切换到核心态,因此线程管理的成本高,开销大。
2.3 多线程模型
1.一对一模型
一个用户级线程映射到一个内核级线程。每个用户进程有与用户级线程同数量的内核级线程。
优点: 当一个线程被阻塞后,别的线程还可以继续执行,并发能力强。多线程可在多核处理机上并行执行。
缺点: 一个用户进程会占用多个内核级线程,线程切换由操作系统内核完成,需要切换到核心态,因此线程管理的成本高 开销大。
刚刚在内核态举例的图,就是一对一模型。
2.多对一模型
多个用户级线程映射到一个内核级线程。且一个进程只被分配一个内核级线程。
优点: 用户级线程的切换在用户空间即可完成,不需要切换到核心态,线程管理的系统开销小,效率高
缺点: 当一个用户级线程被阻塞后,整个进程都会被阻塞,并发度不高。 多个线程不可在多核处理机上并行运行
3.多对一模型
n用户及线程映射到 m 个内核级线程 (n>=m)。每个用户进程对应 m 个内核
级线程。
克服了多对一模型并发度不高的缺点(一个阻塞全体阻塞),又克服了一对一模型中一个用户进程占用太多内核级线程,开销太大的缺点。
2.4 线程的状态与转换
3 处理机调度
调度通俗的来讲,就是指定某种规则来决定处理这些任务的顺序。
3.1 调度的三个层次
1.低级调度(进程/处理机调度)
按照某种策略从就绪队列中选取一个进程,将处理机分配给它。
进程调度是操作系统中最基本的一种调度,在一般的操作系统中都必须配置进程调度。
进程调度的频率很高,一般几十毫秒一次。
2.中级调度(内存调度)
内存不够时,可将某些进程的数据调出外存。等内存空闲或者进程需要运行时再重新调入内存。暂时调到外存等待的进程状态为挂起状态。 被挂起的进程PCB会被组织成挂起队列。
3.高级调度(作业调度)
按照一定的原则,从外存的作业后备队列中挑选一个作业调入内存,并创建进程。每个作业只调入一次,调出一次。作业调入时建立PCB,调出时撤销PCB。
而作业可以简单理解为用户让操作系统启动一个程序(来处理具体的任务)。
三种调度方式的对比
3.2 进程的挂起态与七状态模型
暂时调到外存等待的进程状态为挂起状态(挂起态,suspend)。挂起态又可以进一步细分为就绪挂起、阻塞挂起两种状态
3.3 进程调度
3.3.1 进程调度的时机
进程调度(低级调度),就是按照某种算法从就绪队列中选择一个进程为其分配处理机。
王道给出的示意图如下:
3.3.2 进程的调度方式
- 非剥夺调度方式,又称非抢占方式。 即,只允许进程主动放弃处理机。在运行过程中即便有更紧迫的任务到达,当前进程依然会继续使用处理机,直到该进程终止或主动要求进入阻塞态。
- 剥夺调度方式,又称抢占方式。 当一个进程正在处理机上执行时,如果有一个更重要或更紧迫的进程需要使用处理机,则立即暂停正在执行的进程,将处理机分配给更重要紧迫的那个进程。
4 调度算法(重点!!!)
4.1 调度算法的评价指标
CPU利用率
指CPU忙碌的时间占总时间的比例。
cpu利用率 = 忙碌时间 / 总时间
系统吞吐量
对于计算机来说,希望在尽可能少的时间处理尽可能多的作业,因此,系统吞吐量指的是单位时间内完成作业的数量。
系统吞吐量 = 总共完成的作业数 / 总共使用时间
周转时间与平均周转时间
对于计算机的用户来说,他很关心自己的作业从提交到完成花了多少时间。
周转时间,是指从作业被提交给系统开始,到作业完成为止的这段时间间隔。
它包括四个部分:作业在外存后备队列上等待作业调度(高级调度)的时间、进程在就绪队列上等待进程调度(低级调度)的时间、进程在CPU上执行的时间、进程等待I/0操作完成的时间。后三项在一个作业的整个处理过程中,可能发生多次。
(用户关心)周转时间 = 作业完成时间 - 作业提交时间
(系统关心)平均周转时间 = 各作业周转时间之和 / 作业数
等待时间
指进程/作业处于等待处理机状态时间之和,等待时间越长,用户满意度越低。
- 对于进程 : 等待时间指进程建立之后等待被服务时间之和,而等待I/O完成的期间实际上也是被服务的,所以不计入等待时间。
- 对于作业:不仅要考虑建立进程后的等待时间,还应该考虑作业在外存后备队列等待的时间。
4.2 适用于批处理系统的调度算法
4.2.1 先来先服务(FCFS)
按照作业/进程到达的先后顺序进行服务。
4.2.2 短作业优先(SJF)
最短的作业/进程优先得到服务(所谓 “最短” 指要求的服务时间最短),但是,作业/进程的运行时间是由用户提供的,并不一定真实,也就并不一定能够实现真正的短作业优先!
而短作业优先算法分为两种情况,具体例题如下:
非抢占式
0时刻,P1已经到达,则P1上处理机运行7s,而在此7s中,P2、P3、P4进程均到达,所以在P1结束后优先运行需要服务时间最短的P3。当P3结束后,由于P2、P4所请求的服务时间一致,因此先运行先到达的,即先P2,后运行P4。
抢占式
即使用最短剩余时间优先的算法:每当有进程加入就绪队列改变时就需要进行调度,如果新到达的进程剩余时间比当前运行的进程剩余时间更短,则由新进程抢占处理机。
4.2.3 高响应比优先(HRRN)
FCFS 算法是在每次调度的时候选择一个等待时间最长的作业(进程)为其服务。但是没有考虑到作业的运行时间,因此导致了对短作业不友好的问题。SJF 算法是选择一个执行时间最短的作业为其服务。但是又完全不考虑各个作业的等待时间,因此导致了对长作业不友好的问题,甚至还会造成饥饿问题。
由此,提出了高相应比优先调度算法
该算法是非抢占式的调度算法,只有当前运行的进程主动放弃CPU时,才需要进行调度。每次调度选择响应比最高的进程!
响应比 = (等待时间 + 要求服务时间) / 要求服务时间
前面介绍的三种调度算法一般适用于早期的批处理系统,而后将介绍交互式系统的调度算法。
4.3 适用于交互式系统的调度算法
4.3.1 时间片轮转(RR)
轮流让就绪队列中的进程依次执行一个时间片(每次选择的都是排在就绪队列队头的进程)
例题如下:
时间片大小的选择:
- 如果时间片太大,使得每个进程都可以在一个时间片内完成,则时间片轮转调度算法就会退化成先来先服务调度算法,增加进程响应时间。
- 如果时间片太小,会导致进程切换频繁,系统会花大量时间来处理进程切换,从而导致用于进程执行的时间比例减少。
4.3.2 优先级调度算法
调度时选择优先级最高的作业/进程。分为抢占式和非抢占式。非抢占式只需要在进程主动放弃处理机时进行调度即可,而抢占式还需要在就绪队列变化时,检查是否会发生抢占。
非抢占式
每次调度时选择当前已经到达且优先级最高的进程。当进程主动放弃处理机时发生调度。
抢占式
每次调度时选择当前已经到达且优先级最高的进程。当前进程主动放弃处理机的时候发生调度,当就绪队列发生改变的时候也要检查是否发生抢占。
补充
就绪队列未必只有一个,可以按照不同优先级来组织。另外,也可以把优先级
高的进程排在更靠近队头的位置工作。
根据优先级是否可以动态改变,可将优先级分为静态优先级和动态优先级两种。
静态优先级: 创建进程时确定,之后一直不变。
动态优先级: 创建进程时有一个初始值,之后会根据情况动态地调整优先级。
4.3.3 多级反馈队列调度算法(后续补充)
本文图片出自于王道考研计算机操作系统408公开视频,本文内容仅作为学习笔记交流使用。