#pic_center
R 1 R_1 R1
R 2 R^2 R2
目录
- 知识框架
- No.0 引言
- No.1 进程的概念、组成、特征
- 一、进程的概念
- 二、进程的组成
- 1、PCB进程控制块
- 2、程序段/数据段
- 三、程序是如何运行的?
- 四、进程的特征
- 五、总结
- No.2 进程的状态转换和组织
- 一、进程的状态
- 1、创建态、就绪态
- 2、运行态
- 3、阻塞态
- 4、终止态
- 二、进程的状态间的转换
- 三、进程的组织方式
- 1、链式方式
- 2、索引方式
- 四、总结
- No.3 进程控制
- 一、什么是进程控制
- 二、如何实现进程控制
- 三、如何实现原语的原子性
- 四、进程相关的原语
- 1、实现进程的创建的原语
- 2、撤销原语
- 3、阻塞原语和唤醒原语
- 4、切换原语
- 五、程序是如何运行的?
- 六、总结
- No.4 进程通信
- 一、什么是进程通信
- 二、为什么进程通信需要OS支持
- 三、共享存储
- 四、消息传递
- 1、直接通信方式
- 2、间接通信方式
- 五、管道通信
- 六、总结
- No.5 线程的概念与特点
- 一、什么是线程为什么要引入线程呢
- 二、引入线程后的变化
- 三、线程的属性
- No.6 线程的实现方式和多线程模型
- 一、用户级线程
- 二、内核级线程
- 三、多线程模型
- 1、一对一模型
- 2、多对一模型
- 3、多对多模型
- 四、总结
- No.7 线程的状态与转换
- 一、线程的状态和转换
- 二、线程组织与控制
- No.8 调度的概念、层次
- 一、调度的概念
- 二、调度的三个层次
- 1、高级调度
- 2、低级调度
- 3、中级调度
- 三、七状态模型
- 四、三种对比
- 五、总结
- No.9 进程调度的时机、切换与过程、方式
- 一、进程调度的时机
- 二、进程调度的方式
- 三、进程的切换和过程
- 四、总结
- No.10 调度器和闲逛进程
- No.11 调度算法的评价指标
- 一、CPU利用率
- 二、系统吞吐量
- 三、周转时间
- 四、等待时间
- 五、响应时间
- 六、总结
- 五、响应时间
- 六、总结
知识框架
No.0 引言
No.1 进程的概念、组成、特征
各位同学大家好,从这个小节开始,我们会正式进入第二章,处理及管理相关的内容,那么在这个小节当中,我们会首先来认识一个很重要的概念,叫做进程,在第一章的讲解当中,我们经常会说,系统当中正在运行的程序怎么怎么的,怎么怎么的,偶尔也会提到进程这个术语,对于很多跨考的同学来说,进程和程序这两个概念,其实是比较容易混淆,不易理解的,那这个一会我们会介绍,接下来我们还会介绍,一个进程由哪些部分组成,有什么重要的特征,那首先来看第一个部分进程,
一、进程的概念
的概念根据去年同学们的反馈,这个地方如果直接,抛出一些文字性的描述,那很多,跨考的非科班的同学会比较难理解,所以,我们这次采用一个更贴近大家生活,经验的一种方式来进行讲解,首先来看一下,我在我自己的Windows电脑里啊,打开了任务管理器,那任务管理器当中就可以看到,此时系统当中正在运行的进程,有这么多,那此时如果我想要使用QQ的话,那我打开我的QQ程序,于是我的这个QQ程序就开始运行,那相应的在进程这一栏里,我会看到一个和QQ相关的啊,这样的一个条目信息,而如果说此时我想要同时登录两个,甚至3个QQ号,那我可以再打开两次QQ程序,那在这个时候会发现进程这一栏里,QQ相关的啊条目出现了3条,也就是说在系统当中,此时有3个QQ进程正在运行,虽然说这三次我打开的都是QQ点exe,这个程序,但是这个程序的三次执行,会对应三个不同的进程,如果大家的电脑现在就在身边的话,就可以自己动手看一下,是不是这样的情况,所以其实所谓的程序,它是一种静态的,存放在词盘里的可执行文件,在Windows电脑里就是啊QQ点exe,那么这个可执行文件,其实就是一系列的指令集合,而指令的概念,我们在第一章当中讲解过,而所谓的进程它是动态的,是程序的一次执行过程,也就是说即使是同一个程序,它多次执行,那么每一次的执行,都会对应一个不同的进程,就像我们在这个地方所看到的那这样,所以用这个界面,大家应该能够很直观的体会到,进程和程序,它们的一个区别,那么接下来问题产生了,既然这三个进程,执行的都是同一个程序,那么操作系统在背后,要怎么区分这三个进程呢,不能把它们都叫做腾讯QQ进程吧,所以其实为了解决,
所以其实所谓的程序,它是一种静态的存放在磁盘里的可执行文件。在Windows电脑里就是QQ.exe。那么这个可执行文件,其实就是一系列的指令集合。而指令的概念,我们在第一章当中讲解过。而所谓的进程它是动态的,是程序的一次执行过程,也就是说即使是同一个程序,它多次执行,那么每一次的执行都会对应一个不同的进程,就像我们在这个地方所看到的那这样。所以用这个界面,大家应该能够很直观的体会到进程和程序它们的一个区别。
二、进程的组成
那么接下来问题产生了,既然这三个进程执行的都是同一个程序,那么操作系统在背后要怎么区分这三个进程呢?不能把它们都叫做腾讯QQ进程吧。所以其实为了解决这个问题,操作系统在创建一个进程的时候,会给这个进程分配一个唯一的、不重复的ID,叫做p ID,也就是进程 ID。它就相当于我们人类世界的身份证号,我们每个人的身份证号都是唯一的、不重复的,而 p ID 就是进程的身份证号。那还是让大家看一个直观的例子,我现在正在录制视频,使用的是苹果的电脑,那苹果的电脑有一个叫做活动监视器的一个小工具,它和 Windows 的那个任务管理器其实是一样的,可以用这个小工具来看一下现在在我的系统上正在运行的进程有哪些。在这一栏可以看一下有一个叫做 PID,也就是进程 ID 的一个属性。我们让这些进程根据 PID 的递减的次序来排列,那可以看到各个进程的 PID,它们都是不重复的。那此时我来打开一个叫做 Tapro 的一个应用程序,当我打开这个应用程序之后,大家注意观察这个地方,出现了和它相对应的一个进程的信息,它的 PID 是 2641。那此时我再把这个应用程序给退出,然后再一次打开,有没有发现它的 PID 变成了 2642?刚才是 2641,现在变成了 2642。所以这就能很好的说明一个问题,我们每一次新建一个进程,都会给它分配一个不重复的唯一的 ID,在很多操作系统当中,PID 的分配都是每一次加一这样的一个很简单的策略。可以看到现在系统在背后,他又自己创建了一个新的进程,虽然我不知道这个进程是干嘛的,但是他的 PID 依然是递增的。所以其实回到刚才的这个图,虽然说这些进程,他们的进程的名称都叫腾讯 QQ 32 位,但是他们在背后都有各自的 PID,他们的 PID 肯定是不重复的。
那么接下来问题产生了,既然这三个进程执行的都是同一个程序,那么操作系统在背后要怎么区分这三个进程呢?不能把它们都叫做腾讯QQ进程吧。所以其实为了解决这个问题,操作系统在创建一个进程的时候,会给这个进程分配一个唯一的、不重复的ID,叫做p ID,也就是进程 ID。它就相当于我们人类世界的身份证号,我们每个人的身份证号都是唯一的、不重复的,而 p ID 就是进程的身份证号。那还是让大家看一个直观的例子,我现在正在录制视频,使用的是苹果的电脑,那苹果的电脑有一个叫做活动监视器的一个小工具,它和 Windows 的那个任务管理器其实是一样的,可以用这个小工具来看一下现在在我的系统上正在运行的进程有哪些。在这一栏可以看一下有一个叫做 PID,也就是进程 ID 的一个属性。我们让这些进程根据 PID 的递减的次序来排列,那可以看到各个进程的 PID,它们都是不重复的。那此时我来打开一个叫做 Tapro 的一个应用程序,当我打开这个应用程序之后,大家注意观察这个地方,出现了和它相对应的一个进程的信息,它的 PID 是 2641。那此时我再把这个应用程序给退出,然后再一次打开,有没有发现它的 PID 变成了 2642?刚才是 2641,现在变成了 2642。所以这就能很好的说明一个问题,我们每一次新建一个进程,都会给它分配一个不重复的唯一的 ID,在很多操作系统当中,PID 的分配都是每一次加一这样的一个很简单的策略。可以看到现在系统在背后,他又自己创建了一个新的进程,虽然我不知道这个进程是干嘛的,但是他的 PID 依然是递增的。所以其实回到刚才的这个图,虽然说这些进程,他们的进程的名称都叫腾讯 QQ 32 位,但是他们在背后都有各自的 PID,他们的 PID 肯定是不重复的。
那还有像最后的这一列,他是列出了各个进程的一个对网络流量的使用情况。所以其实操作系统在背后,他不只是记录了各个进程的 PID,除了 PID 之外,他还记录了各个进程的其他的一些信息,比如说刚才我们所看到的,他所属的用户 ID,或者简称 UID。操作系统可以根据 PID、UID 这些基本的进程描述信息,来区分各个进程。还有刚才我们看到的,分配了多少内存,正在使用哪些 IO 设备,正在使用哪些文件,这些信息的记录,可以帮助操作系统实现对系统资源的一个管理工作。另外呢还有刚才我们看到的,CPU 使用时间、磁盘使用情况、网络流量使用情况等等,这些信息可以帮助操作系统实现对进程的控制和调度,等等一系列的管理策略。
那既然操作系统在背后要记录这么多的信息,那么这些信息都会被统一的放在一个叫做 PCB 的一个数据结构当中。它的英文缩写是 Process Control Block,就是进程控制块。总之呢,操作系统他需要对各个并发运行的进程进行管理,而但凡他在管理这些进程的时候,所需要用到的信息,都会放在这个叫做 PCB 的数据结构当中。所以 PCB 是一个很重要的数据结构,它是进程存在的唯一标志。当一个进程被创建的时候,操作系统也会为他创建相应的 PCB。当然这个 PCB 当中又包含了进程的啊 p ID、UID 等等一系列的信息。而当一个进程结束的时候,操作系统就会回收他的 PCB。
1、PCB进程控制块
那在 PCB 当中需要保存的信息,大致上可以分为这样的四类:进程描述信息、进程控制和管理相关的信息、还有资源分配的情况。这三种类型的信息刚才我们都已经介绍过啊。除此之外,还会在 PCB 当中保留啊处理机相关的信息。那只有在 PCB 当中保存了处理机相关的信息,才可以实现进程的切换工作,那这个坑我们先留着之后再来填。
接下来让大家看一个令人脑壳疼的东西啊。我在网上找到了 Linux 的内核源码,然后在一个叫做 sched.h 这样的文件当中,我们就可以看到啊,在 Linux 操作系统当中,它定义的 PCB 长什么样子。在 Linux 当中它的 PCB 的名字叫做 task_struct。有兴趣的同学也可以大家去 Linus 的官网,下载一下它的源码,来看一下这个文件。那在这个 task_struct 里边,它会记录各种各样的信息,比如说这个字段啊 state,这个字段,它其实就是记录了进程当前的状态,而处于就绪态呢、运行态呢还是阻塞态呢等等。那进程的状态,这是我们下一个小节当中会展开介绍的内容。再来看这个字段 fields,这个字段,它记录的是当前进程,它打开了哪些文件,然后还有一个叫做 IO context 的字段,这个字段,它记录的是 IO 管理当中所需要使用的信息。当然这个数据结构里面定义了好多好多字段,大家可以看一下,光是这个数据结构的定义,它就写了 1,900 多行的代码。这么多代码是让人很抓狂的一个事情。
总之呢,我们想要认识 PCB 当中的所有字段,那是不可能的。我们只需要知道 PCB 当中存放的都是操作系统在对进程进行管理的时候所需要的那些信息就可以了。那除了 PCB 之外,进程还有两个很重要的组成部分,一个叫做程序段,一个叫做数据段。刚才我们说过,PCB 它是给操作系统用的一个数据结构,而程序段和数据段,它其实是给进程自己用的。
2、程序段/数据段
那除了 PCB 之外,进程还有两个很重要的组成部分,一个叫做程序段,一个叫做数据段。刚才我们说过,PCB 它是给操作系统用的一个数据结构,而程序段和数据段,它其实是给进程自己用的。
三、程序是如何运行的?
我们具体来看一个例子,在之前的第一章节当中,我们学到了啊,这个程序在运行之前需要编译成二进制的机器指令,而这个程序执行的过程,其实就是 CPU 执行这些一条一条的指令的一个过程。那接下来我们把程序运行的过程再进一步的细化一下,其实我们写完一个程序之后,经过编译、链接等一系列的步骤,最终会形成一个可执行文件,像大家熟悉的 Windows 电脑里,就是 .exe 的文件。那这个可执行文件,平时是存放在硬盘当中的,这个可执行文件当中保存的其实就是我们刚才说的那一系列的指令序列。
而当这个程序要运行之前,需要把它从硬盘读入到内存当中,并且操作系统会建立一个与它相对应的进程。那根据刚才我们的分析,我们知道它会建立相对应的 PCB。那除了 PCB 之外,这个程序的那一系列指令序列,也需要读到内存当中,那这一系列的指令序列,我们把它称作为程序段。那其实这个程序执行的过程,或者说这个进程它执行的过程,就是 CPU 从内存当中读入这些一条一条的指令,然后来执行这些指令。
除了执行这些指令之外,其实在执行指令的过程当中,会有一些中间的数据,比如说我们这定义了一个变量叫做 x,那么这些变量的内容,其实也需要放在内存当中。所以还会有另外一个叫做数据段的区域,用来存放这个程序运行过程当中所产生所需要使用的各种数据,就比如说我们定义了哪些变量,这些信息就是放在数据段里的。所以一个进程的实体,它由 PCB、程序段和数据段这么三个部分组成。
我们之前一直在说进程有哪些部分组成,但其实更严格的来说,应该是说进程实体有哪些部分组成。进程实体,或者说进程印象,它是动态的,而进程实体、进程印象,它是静态的。我们可以把进程实体理解为是这个进程在动态执行过程当中某一时刻的一个快照、一个照片。进程实体能够反映这个进程在某一个时刻的状态,比如说这个进程运行的过程当中,x 的值这个变量的值本来是一,但是在进行了加加这个操作之后,x 的值就会变成 2。所以在进程的运行过程当中,进程实体它是在不断变化的。所以准确的说,我们应该说进程实体由 PCB、程序段和数据段这样三个部分组成。
不过除非题目特别考察进程和进程实体的区别,不然大家也可以认为所谓的进程就是进程实体,没必要去钻这个牛角尖扣这个字眼。那 PCB 是给管理者,也就是给操作系统使用的,而程序段和数据段里面的内容,是给进程自己使用的,和进程自己的运行逻辑有关。所以在引入了进程实体的概念之后,我们可以把进程的定义为这样:进程它是进程实体的一个运行过程,是系统进行资源分配和调度的独立单位。进程是资源分配的独立单位,这一点很好理解,从刚才活动监视器这我们也可以看到,操作系统是以进程为单位,给各个进程来分配这些资源的,比如说内存。所以进程是资源分配的独立单位。
那这个地方还涉及到另一个概念,叫做进程的调度。其实所谓的调度,就是指操作系统决定让哪个进程上 CPU 运行。进程的调度,相关的内容,我们会在之后的小节当中有更进一步的学习。这先不展开。最后进程还拥有结构性,就是指每个进程都会有一个 PCB、一个程序段和一个数据段。那所有的这些特性大家都只需要理解,不需要啊死记硬背。
四、进程的特征
好的,那么这个小节,我们介绍了进程这个很重要的概念,进程或者说进程实体,由 PCB、程序段和数据段这三个部分组成。PCB 是一个很重要的数据结构,它是进程存在的唯一标志。操作系统就是通过 PCB 里边记录的这些各种各样的信息,来对各个进程进行管理的,所以但凡是在操作系统管理进程,所需要的数据肯定都是放在 PCB 当中。而进程它自己所需要的数据,是放在程序段和数据段当中的。另外需要注意的是,进程的动态性是它最基本的特性,并且还需要注意,进程它是独立获得资源、独立接受调度的一个基本单位。让大家注意这一点的原因是,在引入了线程之后,进程就不再是接受调度的基本单位了,但是进程依然是获得资源的基本单位,这点还会经过后续的小节进行进一步的讲解。这暂时先不展开。
五、总结
我们介绍了进程这个很重要的概念,进程或者说进程实体由PCB,程序段和数据段这样三个部分组成,PCB是一个很重要很重要的数据结构,它是进程存在的唯一标志,操作系统就是通过,PCB里边记录的这些各种各样的信息,来对各个进程进行,管理的,所以但凡是在操作系统管理进程,所需要的数据,肯定都是放在PCB当中,而进程他自己所需要的数据,是放在程序段和数据段当中的,另外呢需要注意的是,进程的动态性是他最基本的特性,并且还需要注意,进程他是独立获得资源,独立接受调度的一个基本单位,让大家注意这一点的原因是啊,在引入了县城之后,晋城就不再是接受调度的基本单位了,但是晋城依然是获得资源的基本单位,这点还会经过后续的小节,进行进一步的讲解,这暂时先不展开,好的,那么以上就是这个小节的全部内容,
No.2 进程的状态转换和组织
在这个小节中,我们会学习进程的状态和状态的转换相关的知识点。接下来,我们会介绍进程所拥有的各种各样的状态,以及它们之间在什么情况下需要转换。
另外,我们还会介绍进程的组织方式的问题,也就是各个进程的 PCB 之间要,呃,用什么样的方式把它们组织起来。这样的一个问题。
一、进程的状态
1、创建态、就绪态
首先,我们来看一下进程有哪些状态。在上个小节当中,我们提到过,其实我们的程序也就是可执行文件,平时是存放在硬盘里的。而当这个程序想要执行的时候,需要把这个可执行文件把它调入内存。同时,操作系统会为它建立相应的 PCB,也就是建立一个相应的进程。那,当一个进程正在被创建的这个期间,啊,这个进程的状态就是处于创建态。
在这个阶段,操作系统会给这个进程分配相应的系统资源,比如说给他分配一些内存空间。另外呢,在这个阶段,操作系统也会完成对 PCB 的一个初始化的工作。而当一个进程完成了创建工作之后,他就会进入一个新的状态,叫做就绪态。处于就绪态的进程其实是已经具备了,啊,运行的条件,只不过此时 CPU 比较忙,他还没有空闲,所以 CPU 暂时不能为这个进程服务。
2、运行态
那一个系统当中,可能会有很多很多个处于就绪态的进程。那么,当 CPU 空闲的时候,操作系统就会从这些,呃,处于就绪态的进程当中,选择其中的一个,让他上 CPU 运行。而如果一个进程,此时正在 CPU 上运行的话,那么这个进程就处于运行态。
那么经过之前的学习,我们知道一个进程它正在运行,意味着此时 CPU 呃,正在处理这个进程背后的那个程序,也就是呃,CPU 正在执行这个进程相应的那些指令序列,比如说 CPU 执行了进程 2 的指令一,指令 2,指令 3。
3、阻塞态
那我们假设此时进程 2 的指令 3 是发出了一个系统调用,而这个系统调用是请求操作系统给他分配打印机资源。而此时打印机设备,他很忙,他正在为别的进程服务,所以这个打印机资源暂时不能分配给进程 2。所以这个进程 2 接下来的这个指令,也就是要往打印机输出数据,这条指令就没办法往下执行。
那既然这个进程接下来的这些指令暂时不能往下执行的话,那么显然,我们不应该让这个进程一直占用着 CPU 资源,所以类似于刚才我们所说的这种情况,很多时候,进程在运行的过程当中,有可能会请求等待某个事件的发生,比如说像刚才我们所说的,他会等待系统给他分配某一种系统资源,或者他需要等待其他进程的响应等等。
总之,这个进程在运行的过程当中,有可能会主动地请求等待某个事件的发生,而当这个事件发生之前,这个进程是没有办法继续往下执行的,所以在这个时候操作系统就会呃,剥夺这个进程对 CPU 的使用权,让这个进程下 CPU,并且让它进入到一个新的状态,叫做阻塞态。
也就是说,这个进程因为等待某个事件而被阻塞了。那当这个 CPU 再次空闲之后,操作系统又会选择呃一道处于就绪态的进程,让他上 CPU 运行。
4、终止态
接下来的故事是这样的,这个打印机设备之前不是正在为别的进程服务吗?那如果说这个打印机的服务已经结束,那这个打印机就会空闲下来。所以当打印机空闲下来的时候,它就可以分配给刚才请求打印机的那个进程,也就是进程 2。所以当操作系统把这个打印机资源分配给进程 2 的时候,这个进程 2 等待的事件其实就已经发生了。此时操作系统会让这个进程 2 从阻塞态再次回到就绪态。
也就是说,当他等待的这个事件发生了之后,这个进程就再次啊拥有了上处理机运行的条件。那我们让这个故事继续下去,假设此时正在 CPU 上运行的这个进程,进程 1,他已经运行结束了。
那在他运行结束的时候,他会发出一个叫做 exit 的系统调用。那这个系统调用,其实就是要请求操作系统终止这个进程。那此时,这个进程的状态就会变成终止态。然后操作系统会让这个进程下 CPU,并且做一系列的善后的工作,他会回收这个进程所占有的呃各种资源,包括什么内存空间啊,什么打印机设备啊等等。总之所有的资源都需要回收,并且最后他还会呃回收这个进程的 PCB。而当终止进程的这些工作完成了之后,这个进程就从这个系统当中彻底消失了。
二、进程的状态间的转换
好的,那么我们再用一个图,把刚才所提到的这些进程的状态和他们的转换再给穿一下。一个进程在运行之前需要被创建。在创建的过程当中啊,系统会完成一系列相应的工作,包括啊新建 PCB,还有给这个进程分配一系列的资源等等。那如果一个进程正在被创建的话,那这个进程此时就是处于创建态的。
当一个进程被创建完毕之后,他就拥有了可以上处理机上 CPU 运行的这种条件。那这个时候进程就进入了就绪态,也就是说处于就绪态的进程,他其实只差处理机这种资源,其他他所需要的资源,他已经呃都具备了。那如果处于就绪态的一个进程被操作系统调度,那这个进程就可以上处理机运行。
当他在处理机上运行的时候,他就处于运行态,也就是说,正在处理机上运行的进程其实是啊既拥有了他所需要的其他所有的那些条件和资源,同时他也拥有了处理机这种资源。而有的时候,正在运行的进程可能会请求呃等待某些事件的发生。
在这个事件发生之前,这个进程是没有办法继续往下执行的,所以在这种情况下,进程不应该一直占用着处理机资源。所以,此时这个进程应该被剥夺处理机资源,同时除了处理机资源之外,他还在等待其他的某一种资源,或者说等待其他的某一种事件的发生。那如果说处于阻塞态的进程,他等待的事件发生了,那这个进程就可以从阻塞态又回到就绪态。
也就是说,当他回到就绪态,就说明这个进程他已经拥有了除了处理机之外的所有的他想要的那些资源。所以从刚才的这个讲解过程当中,我们会发现,运行态到阻塞态的这个转换,其实是进程自身主动的一种选择,主动的行为。
一般来说,都是进程通过系统调用的方式来申请某一种系统资源,或者请求等待某个事件的发生。所以这个转换的过程,是进程主动选择的。而阻塞态到就绪态的转变,它并不是进程自身能够控制的。比如说一个进程,他正在等待打印机资源,那么这个打印机资源什么时候分配给他,这并不是这个进程能够说了算的。所以阻塞态到就绪态的转换,他是一种被动的行为,他并不是进程自己可以控制的。
所以大家需要注意的是,一个进程不可能直接从阻塞态转换为运行态,也不可能直接从就绪态转换为阻塞态,因为进程要变成阻塞态,那肯定是需要进程主动请求,进程要发出这种主动请求,那就意味着这个进程肯定是正在 CPU 上运行才可能发出这种主动请求。所以说只可能从运行态转换成阻塞态,而不可能从就绪态转换成阻塞态。
那在之前的讲解中,我们也提到过,处于运行态的进程,他可以主动地请求啊运行结束,或者说如果一个进程,他在运行的过程当中,遇到了一些不可修复的错误,比如说整数除以 0 这样的错误,那在这种情况下,这个进程也应该被终止,那在操作系统啊,对这个进程做相应的终止工作的时候,这个进程就处于终止态。
此时操作系统会回收呃进程所拥有的各种资源,并且会撤销它的 PCB。那最后,我们还要强调一个刚才没有提到的状态的转换。有的时候,进程可以直接从运行态转换成就绪态,比如说操作系统给进程分配的时间片用完了的时候,进程就会从运行态转换成就绪态。
什么叫时间片用完呢,还记不记得我们在第一章当中啊提到过时钟中断?一个进程本来正在处理机上运行的好好的,但是此时如果 CPU 收到一个时钟中断的信号,然后发现这个进程已经运行了很长时间了,呃不应该让他继续往下执行了,那这种情况就是所谓的时间片用完的一个状态。
时,这个进程就应该被剥夺 CPU 的使用权,让它从运行态回到就绪态。因为在这种情况下,实际上进程仍然具备继续执行的条件,只是被剥夺了处理器的执行权,无需等待除了处理器之外的其他事件发生。因此,进程从运行态回到了就绪态。
这涉及到了经典的进程五状态模型,也被称为“丁字模型”。其中,运行态、就绪态和阻塞态是基本状态,因为进程的大部分生命周期都处于这三种状态中。值得强调的是,在单核 CPU 环境下,同一时刻最多只能有一个进程处于运行态,而在多核 CPU 环境下,多个进程可以并行运行。
另外,需要注意的是,阻塞态有时也被称为等待态,创建态也叫新建态,终止态也叫结束态。这些都是相同概念的不同称呼,大家要留意这些术语。
为了记录进程的状态,操作系统会在进程的 PCB 中有一个名为 “state” 的变量,用来表示当前状态。例如,可以使用数字 1 表示创建态,数字 2 表示就绪态,以此类推。
三、进程的组织方式
1、链式方式
操作系统会以有组织的方式管理各个状态的进程 PCB。在链式方式中,操作系统管理一系列队列,每个队列代表一种状态,其中存放相应状态的进程 PCB。例如,有一个执行队列指针,它指向正在运行的进程的 PCB;就绪队列指针指向处于就绪态的进程的 PCB 队列。操作系统可能将优先级较高的进程的 PCB 放在队列的前端。同样,阻塞队列也是类似的,可以根据不同的阻塞原因划分多个子队列,例如等待打印机资源的队列和等待磁盘资源的队列。
2、索引方式
此外,操作系统也可以使用索引方式来组织进程的 PCB。对于每种状态,操作系统会建立相应的索引表,每个索引项指向相应状态的一个进程的 PCB。
四、总结
总而言之,进程状态之间的转换和进程的组织方式是操作系统中的重要概念。进程的状态转换是由进程主动请求以及操作系统调度等因素共同影响的结果。而进程的组织方式通过链式或索引方式,将不同状态的进程 PCB 有组织地管理起来,以便操作系统进行调度和管理。希望通过这些内容的解释,能够让大家对进程状态和状态转换有更加清晰的理解。
No.3 进程控制
一、什么是进程控制
在这个小节中,我们会学习进程控制相关的知识点。那么,什么是进程控制呢?我们的王道书上给出了这样的一些描述:进程控制的主要功能是对系统当中的所有进程实施有效的管理。它具有创建新进程、撤销有进程实现状态、进程状态转换等功能。那其实说白了,进程控制它就是比如说创建一个新进程,那不就是让一个进程从无到有啊,从创建态再到就绪态,这是创建新进程所需要干的事情。那撤销一个已有进程,不就是让进程进入终止态,然后最终把这个进程干掉的一个过程吗?所以其实所谓的进程控制,就是要实现这些进程的状态转换。
那么在进程的状态转换的时候,操作系统需要做一些什么事情呢?这就是这个小节当中,我们要讨论的内容。
刚才我们简要的了解了什么是进程控制。接下来我们会介绍怎么实现进程控制。啊,需要用原子性来实现。那这个一会会展开之后,我们会介绍几个进程控制相关的原语。他们分别需要实现哪些功能。
二、如何实现进程控制
啊刚才提到进程控制,也就是进程的状态转换,相应的处理是需要,用原语来实现的,而原语这个概念我们在第一章当中,提到过,操作系统的内核中有一些特殊的程序,它叫原语,原语这种程序,它的执行是具有原则性的,也就是说这个程序,运行是必须一气呵成的,中间不可以被中断,也就是说,实现进程的状态转换这个事情,中间的一系列操作必须一气呵成,那么接下来,我们来考虑一下这样的问题,为什么进程控制,或者说进程的状态转换,这个过程需要一气呵成呢,我们结合上一小节
当中学习到的知识,我们知道在PCB当中会有一个变量,用来表示进程当前所处的状态,比如说这个state变量,当它为一的时候,我们认为它是在就绪态,当它为2的时候在阻塞态,那么如果一个进程他处于就绪态,state等于一的话,那这个进程的PCB,肯定是需要挂在就绪对列里的,而如果state等于2的话,那么这个进程的PCB,就应该被挂在阻塞对列里,那么接下来我们来考虑这样一个事情,我们知道处于阻塞队列的这些进程,他肯定是在等待某种事件的发生,那假设现在这个进程2,也就是PCB 2所对应的那个进程,他所等待的事件已经发生了,那么在这种情况下呃,这个进程,是不是应该从阻塞态转换为就绪态呢,所以操作系统当中的内核程序,就需要把这个进程的状态,从阻塞态变为就绪态,那进行状态转换的这,个过程他至少需要做这样的两件事情,第一件事要把PCB当中state这个,变量从2变为1,第二件事,他还需要把这个PCB2,从阻塞队列当中摘出去,然后挂到就绪队列当中,所以操作系统,在让这个进程的状态发生,转换的过程当中,他至少需要干这样的两件事,那么接下来我们来考虑这样一个事情,假设现在state一已经被它设为了一了,而在完成了这一步之后,突然又检测到了一个中断信号,那么既然检查到了中断信号,那系统肯定需要对这个中断进行处理,在这个时候呃PCB当中state等于一,也就是说从state这个变量来看,这个呃进程它的状态是就绪态,但是从它所处的对列来看,这个PCB 2此时又还是在,呃这个阻塞队列当中,所以这就导致了PCB2当中的这个变量,所表示的状态,和PCB2它所处的这个对列,这两个信息对不上了,所以说,如果操作系统让这个进程的状态,转换的这个,中间处理的步骤不能一气呵成的话,就有可能会出现,我们在这个地方所看到的,这种啊,某些关键的数据结构,信息不统一的情况,那这些数据结构是非常重要的,这有可能会影响到操作系统啊,进行后续的别的一些工作,可能会让系统出错,所以讲到这大家应该就可以明白,为什么进程的状态转换,或者说进程控制的过程,需要一气呵成了,那刚好原语这种特殊的内核程序,它具有一气呵成不,可被中断的这种美好的性质,所以我们可以用原语这种特殊的程序,来实现一气呵成这样的事情,那么接下来我们,
三、如何实现原语的原子性
我们要探讨的问题是,为什么源于这种特殊的程序,它可以一气呵成不被中断呢,其实它的这种原子性,是用两个特权指令,关中断和开中断这两个指令来实现的,我们来看一下这两个指令的作用,那假设这是一个正在运行的内核程序,那CPU会依次执行这些指令,并且根据第一章的讲解我们知道,CPU每执行完一条指令之后,他都会例行的检查,是否有中断信号需要处理,那如果说他在执行了指令2之后,CPU发现此时有一个中断信号,那在这种情况下,CPU就会暂停执行当前的这个程序,转而执行一个处理中断的程序,那等这个中断处理完成之后,他才会再回到原来这个程序,继续往下执行,那这是我们之前认识到的情况,就是呃CPU每执行完一条指令,他都会检查,是否有外部中断信号需要处理,那接下来我们再来看一下,如果执行了关中断指令,会发生什么情况,假设此时CPU,正在依次的执行这些指令,然后当他执行了关中断,这条特权指令之后,CPU就不再例行检查中断信号了,所以接下来CPU会继续往下执行,那如果说此时,他执行了指令a的这个过程当中,呃有一个外部中断信号到来了,但是此时他并不会像之前一样,例行的检查是否有中断信号,而是会继续往下处理,一直到CPU执行了开中断指令之后,他才会恢复以前的那种习惯,也就是每执行完一条指令,那就会检查一下此时是否有嗯,外部中断信号需要处理,所以当他执行了开中断指令之后,他会发现哎,之前有一个中断信号我还没有处理,所以在这个时候,CPU才会转转向执行中断处理程序,所以从刚才这个例子当中,我们就可以看到,在关中段和开中段这两条指令中间的,这一系列的指令序列,他们的执行肯定是不可被中断的,这样的话,就实现了我们,开篇提到的所谓的原子性,这段指令序列的,执行肯定是一气呵成的,他中间不可能再被中断,所以,这是关中段指令和开中段指令的一个,特殊的作用,那显然,这两个指令他们肯定是特权指令,那接下来我们来思考一个问题,如果这两个特权指令,允许普通的用户程序使用的话,会发生什么情况呢,那是不是就意味着,我可以在我的程序开头,就植入一个关中断指令,然后一直到我的程序末尾才,再执行开中断指令,这样的话,只要我的程序上CPU运行了,那我的程序肯定会一直霸占着CPU,而不会被中断,那显然这种情况是不应该让它发生的,所以关中段指令和开中段指令,他们是特权指令,只能让内核程序使用,而不能让普通的用户程序使用,好的,那么到目前为止我们知道了两个事情,第一,进程控制或者说进程的状态转换,这个事情必须一气呵成,而想要做到一气呵成,我们可以用原语这种特殊的,程序来实现,而原语的实现,需要由开中段指令和关中段指令来,配合着完成,那接下来我们要讨论的问题是
四、进程相关的原语
1、实现进程的创建的原语
进程控制相关的这些原语,或者说相关的这些特殊的程序,他们在背后需要完成一些什么事情呢,首先来看第一个原语啊,这个原语是用于实现进程的创建的,如果操作系统要创建一个进程,那么他就必须使用创建原语,那么这个创建原语,他会干这样的几件事情,首先是要申请一个空白的PCB,因为PCB是进程存在的唯一标志嘛,所以要创建一个进程,当然是需要创建一个和他相对应的PCB,另外呢,还会给这个进程分配他所需要的资源,比如说像内存空间等等,然后还会,把这个PCB的内容,进行一些初始化的工作,比如说分配p i d,设置u i d等等,最后他还会把这个PCB,啊插入到就绪队列,所以说创建原语,让一个进程从创建态进入到了就绪态,把它放到了就绪队列里,那有些比较典型的事件会引起啊,操作系统使用创建源语创建一个进程,比如说当一个用户登录的时候,操作系统会给这个用户,建立一个啊与他对应的用户管理进程,或者用户通信进程等等,或者发生作业调度的,时候也会创建一个进程,根据去年的反馈,很多同学不知道作业到底是什么,其实作业就是,此时还放在呃外存里的那些,还没有投入运行的程序,所以所谓的作业调度就是指,从外存当中挑选一个程序,让他把它放入内存,让他开始运行,我们知道,当一个程序要开始运行的时候,肯定是需要创建和他相对应的进程的,所以当发生作业调度的时候,就需要使用到这个创建原语,另外呢有的时候,一个进程可能向,操作系统提出某些请求,然后操作系统会,专门建立一个进程来处理这个请求,还有的时候,一个进程也可以主动的请求,创建一个紫进程,总之发生这些事件的时候,都会引起啊系统创建一个新的进程,也就是说他会使用到这个创建原语,那接下来要看的,
2、撤销原语
那是撤销原语,撤销原语是呃,要终止一个进程的时候使用的,使用了撤销原语之后,就可以让一个进程从某一种状态,转向终止态,最终这个进程从系统中彻底消失,那撤销原语需要做这样的一些事情,首先既然要撤销一个进程,那肯定需要找到这个进程相应的PCB,那如果说这个进程此时正在运行的话,那就需要立即剥夺他的CPU使用权,然后把CPU分配给其他进程,同时操作系统在杀死一个进城的时候,还会杀死所有他的子进城,并且这个进城被撤销之后,他之前所占有的那些资源应该,归还给他的父进城,最后的最后,还需要把这个进城的PCB,从系统中删除,那这样的话这个进城就彻底的完蛋了,有的同学可能不理解子进程,复进程这样的概念,我们来看一个很实际的例子,这是我现在正在录视频的时候,使用的电脑,这个界面显示的是此时我的电脑当中,正在运行的各种进程,这个界面中的这种显示方式,其实就反映了这些,呃进程之间的父子关系,可以看到这儿有一个呃PID为0的进程,它是最祖先的一个祖先进程,然后这个祖先进程,它创建了一个PID为一的进程,这个进程叫做launch,其实它就是我们在第三章会学习到的,所谓的装入程序,或者叫装入进程,在开机了之后,我们启动的所有的别的那些进程,其实都是这个装入进程来启动的,所以别的那些进程,都是这个装入进程的紫进程,那除了他之外,其他的那些进程,也可以创建自己的紫禁程,来完成相应的一系列工作,比如说访达这个呃进程,他就创建了这几个他自己的紫禁程,那这样的设计方法有什么优点呢,我们可以想一下,刚开始系统中几乎所有的资源,都是这个进程所拥有的,比如说我的电脑里8 g b的内存,全部是他所拥有的,那之后,当他在建立自己的这些紫禁城的时候,他可以按照这些紫禁城的需要,把自己手里的那些资源,再分配给他手底下的这些进程,比如说他本来手里有8GB的内存,那他把其中的50,兆字节分配给了这个进程,把54.5兆字节分配给了这个进程,而当他的这些子进程终止了之后,那当然是需要把自己手里的这些资源,还给他们的,附进程也就是上面的这个进程,所以回到刚才我们提到的这个地方,相信大家就更容易理解了,其实我们的操作系统当中的各个进程,他们之间的关系是一种竖形的结构,系统中的0号进程和1号进程,是最祖先的两个进程,然后这两个进程,又依次创建了他们的紫进程,各个进程又可以再创建各自的紫进程,所以这些进程之间的关系,其实是一种竖形的结构,不过这个并不是我们操作系统,这一门课要考察的重点,只是为了让大家能够更深入的理解,而这提到的这两个特性,希望没把大家绕晕,那我们回到正题继续往下,很多事件,有可能会引起一个进程的终止,比如说一个进程自己请求终止,也就是他呃使用了exit这个系统调用,那这种情况下,操作系统在背后,就会需要使用到这个撤销原语,来把这个进程撤销掉,另外呢,如果一个进程做了一些非法的事件,比如说整数除以0,或者非法使用特权指令,这种情况也会被操作系统强行的撤销,强行把它干掉,还有一种情况,有时候是用户会选择杀掉一个进程,比如说我们在使用Windows电脑的时候,经常出现卡死的情况,那这种情况下,很多同学喜欢用这样的方式,打开任务管理器,然后结束,掉呃某一个卡死的进程,那这种就是外界干预的情况,那接下来我们要看的,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JciHqMAq-1692438038885)(https://cdn.staticaly.com/gh/zben777/figures@main/img/202308111555061.png)]
3、阻塞原语和唤醒原语
那是阻塞元语和唤醒元语啊,这个小节的内容确实比较多,可能很多同学听到这就已经,比较疲惫了,但是其实我们这些元语,他到底要干什么,这些事情我们并不需要死记硬背,我们只需要理解他背后的过程就可以,嗯考试的时候,不可能让你默写这些东西的,所以我们着重以理解为主,大家不需要刻意的记忆,那回到这,有的时候,一个进程可能会从运行态,进入到阻塞态,那在这种情况下,操作系统就会,在背后执行一个阻塞言语,来实现这个状态的转换,阻塞一个进程需要做的事情啊,比较简单,首先是找到这个进程对应的PCB,然后需要保护啊进程运行的现场,什么叫保护进程运行的现场,这个我们一会再解释,这又是一个比较庞大的话题,另外呢系统还需要把,PCB当中的状态信息设置为阻色态,然后然后让这个进程下处里积,并且把它插入到相应的等待对列当中,那经过上个小节的学习我们知道,一个进程需要被阻塞,那肯定是因为他主动请求,要等待某个事件的发生,而如果这个进程,他所等待的事件发生了之后,这个进程就会被唤醒,也就是说,操作系统会让这个进程的状态,从阻塞他,又回到就绪他,那在这个时候就会需要使用到,唤醒原语,唤醒原语需要做这样几个事情,首先要找到他的PCB,然后把PCB从等待对列当中移除,然后把它设置为就绪态,并且把PCB插入到就绪对列当中,等待被调度,这两个原语做的这些事情啊,相信都不难理解,那需要注意的是啊,一个进程因为什么事情被阻塞,就应该被什么事情给唤醒,所以啊唤醒原语和阻塞原语,他们必须是成对使用的,那接下来我们再来认识最后,
4、切换原语
后一个原语叫做切换原语,切换原语会让此时,正在处于运行态的进程,下处理机,让他回到就绪队列,并且从就绪队列当中,选择一个处于就绪态的进程,让他上处理机运行,所以切换原语会让两个进程的,状态发生改变,那切换原语需要做这样的一些事情,首先是需要把进程的运行环境信息,存到PCB当中,什么叫进程的运行环境信息呢,这点涉及到一些硬件的知识,我们一会再展开细聊,另外呢他还会把,呃进程的PCB移到相应的对列,比如说让这个下处理机的进程的PCB,回到继续对列当中,另外呢他还会挑选了一个进程,让他上处立即运行,并且更新他的PCB的内容,同时他还会从这个进程的PCB当中,恢复这个进程所需要的运行环境,那什么叫保存运行环境,什么叫恢复运行环境,这是啊比较难理解的地方,接下来我们得深入探讨一下这个问题,那在之前的学习中我们认识到了一个
五、程序是如何运行的?
程序的运行,需要经历这样一系列的流程,程序运行之前,需要把它相应的这些呃指令,把它放入到内存当中,然后CPU,从内存中读取这些一条一条的指令,并且执行,但是接下来我们要拓展一个,呃更深层的细节,CPU在执行这些指令的过程中啊,需要进行一系列的运算,那么CPU当中会设置很多的寄存器,来存放这些指令,这些程序在运行过程当中,啊所需要的某些数据,总之寄存器,就是CPU里边用于存放数据的一些,呃地方,那CPU当中会有各种各样的寄存器,比如说我们之前提到过PSW,就是程序状态字寄存器,CPU的状态内核态还是用户态啊,这个状态信息就是保存在PSW,啊这个寄存器当中的,当然除了CPU状态信息之外,PSW中还会保存别的一些信息,那这我们就不展开,这是计算机组成原理里边,需要学习的地方,另外CPU中还会有一个比较关键的啊,寄存器叫做PC,也就是程序计数器寄存器,这个寄存器里边存放的是,接下来需要执行的指令,它的地址是多少,那这点我们一会结合实力就,很好理解了,另外CPU当中还会有一个指令寄存器,这个寄存器当中存放的是当前CPU,正在执行的那条指令,还有呢CPU中还会有一些其他的,呃通用的寄存器,可以用来存放一些别的必要的信息,等等等等,总之CPU当中会有一系列的寄存器,我们这只列举了几个,操作系统这门课当中啊,大家需要稍微的了解一下的啊计算器,那接下来我们来分析一下,这样的一些指令序列的执行,在背后发生了什么样的事情,我这自己胡乱写了4条指令,这4条指令所,完成的事情就是定义了一个叫做,x的变量,并且实现了x加加的操作,那假设此时CPU正在执行的是指令一,那么他会把指令一的内容读到IR,也就是指令寄存器当中,并且程序计数器这个寄存器当中,会存放,接下来他应该执行的那一条指令,也就是指令2的地址,那此时CPU执行指令一,他发现,指令一是让他往内存的某一个地方,写入一个呃,变量x的值,那CPU执行指令一的时候,就会往内存的某一个地方,写入变量x的这个值,也就是一,那执行完指令一之后,CPU就会开始执行下一条指令,而从PC这个计算器当中,他就知道,下一条要执行的指令应该是指令2,所以接下来他会取出指令2,把指令2的内容放在呃IR,也就是指令计存器当中,同时PC的内容也更新为再下一条指令,那指令二是让CPU把变量x的值,把它放到某一个呃通用寄存器当中,所以CPU会从内存中取出这个,x变量的值,把它放到通用寄存器当中,于是这个计存器的内容就变成了一,那这样的话就执行完了指令2,那再接下来,CPU又要执行再下一条指令,所以他会取出指令3,然后PC的内容同样的也会更新,那指令3,是让他把计存器当中的这个数据,进行加一的操作,所以这个通用计存器中的值,就会从一变成2,再接下来CPU又会执行再加一条指令,那么此时执行的这条指令,指令4,是让他把这个通用计存器当中的内容,把它写回到变量x,所存放的这个位置当中,所以执行了指令4之后,就会把内存当中x的值从一变成了2,所以可以看到,我们执行x加加这样的操作,其实在背后,CPU是执行了一系列的,更基本的那些指令,才完成了这个事情,并且从刚才讲的这个过程当中,我们会发现,这些指令顺序执行的过程当中,有很多中间结果,是放在这些寄存器当中的,比如说x加加这个操作,刚开始,其实只是把它放在了通用寄存器里,而并没有写回内存,但是需要注意的是,这些寄存器并不是这个进程所独属的,如果其他进程上CPU运行的话,那么这些寄存器也会被,其他进程所使用,那这会发生什么情况呢,我们再把这个故事从头捋一遍,现在这个CPU,它要依次的执行这些指令,那刚开始执行指令一指令2 指令3,当他执行了指令3之后,呃寄存器里的这个值变成了2,而此时,如果说他要转向执行另一个进程,会发生什么情况呢,刚才我们说到如果另一个进程上CPU,运行的话,那么,另一个进程也会使用到这些寄存器,所以另一个进程在上CPU运行的时候,有可能会把,前一个进程在寄存器当中,保留的这些中间结果给覆盖掉,比如说它覆盖成了这个鬼样子,那我们之前的这个进程不是呃,执行到了指令3吗,因为他的前三条指令,执行的那些中间结果都已经被覆盖了,所以,这个进程已经没有办法再往下执行了,所以为了解决这个问题,可以采取这样的策略,当一个进程他要下处理机的时候,可以把他之前,呃运行的这个运行环境的信息,把它保存在自己的PCB当中,当然这个PCB当中,并不需要把所有的寄存器信息都保存,下来,只需要保存一些必要的信息就可以了,比如说PSW PC还有这个通用寄存器,那这个进程执行了前三条指令之后,它的运行环境是这个样子的,我们把它放到了PCB当中,接下来才可以切换成别的进程,那接下来别的进程在使用CPU的时候,可能会往这些计存器当中,写各种各样的数据,总之之前那个进程的数据,有可能会被覆盖,但是当之前的这个进程需要重新回到,呃CPU运行的时候,操作系统就可以根据之前,保存下来的这些信息,来恢复它的运行环境了,那把它的运行环境恢复之后,CPU就知道接下来他要执行的是指令4,并且此时通用计存器,当中存放的数值是2,所以既然接下来要执行的是指令4,那CPU就会根据PC的这个指向,把指令4的内容,取到呃IR这个计算器当中,然后让PC指向下调指令,同时CPU开始解析这条指令时,到底是要干什么,他发现指令4是让他,把寄存器当中的内容,写回到x存放的位置,所以接下来,他就可以把2这个内容写回到,x的这个位置,于是,x加加这个操作就真正的被完成了,总之呢这个地方讲了这么多的内容,想让大家知道的就是,什么叫做进程的运行环境,其实所谓的运行环境,或者说进程上下文,它就是进程在运行过程当中,寄存器里存储的那些中间结果,当一个进程需要下处理机的时候,需要把它的这个运行环境,把它存到自己的PCB当中,而当一个进程,需要重新回到CPU运行的时候,就可以从PCB当中,恢复他之前的这个运行环境,让他继续往下执行了,所以保存进程的运行环境,和恢复进程的运行环境,这是实现进程,并发执行的一个很关键的一个技术,那这个小节的干货
六、总结
比较多我们讲了一些,涉及底层硬件的一些知识,可能学过祭祖的同学觉得这些,其实都很好理解,但是我们又不得不照顾到一些,跨考的同学,和一些不考祭祖的同学,那在操作系统这门课当中,硬件相关的知识我们不需要去深究,只是为了让大家理解其中的某一些,很关键的操作系统概念而,又不得不提一些硬件的知识,毕竟,操作系统是最接近硬件的一层软件嘛,所以中间扯这么多,也是为了让大家能够更好,更深入的理解,那大家需要注意一下原语这个概念,它使用关中段和开中段来实现,它的执行必须一气呵成不可中断,之后我们介绍了一些,进程控制相关的原语,各个原语它中间做了各自的事情,但是这些都不需要死记硬背,其实无论是哪一个控制言语,他所要做的无非就是这么三件事,第一就是更新PCB当中的一些信息,第二是把PCB插入到合适的对列,第三向进程创建和进程终止的时候,有可能还需要分配和回收,这个进程的资源,那更新PCB的信息,主要是修改这个进程的状态,也就是state那个变量,或者就是呃,往PCB当中保存进程的运行环境,或者从PCB恢复进程的运行环境,总之我们了解了这些控制言语,背后做的事情,能够帮助我们更好的理解进程管理啊,处理及管理这一系列的知识,但是这些内容确实不需要死记硬背,所以虽然这个小节看起来内容很多,但是更多的都是理解性的东西,大家不需要花时间去记忆,希望大家不要惊慌,好的那么这就是这个小节的全部内容,同学们辛苦了
No.4 进程通信
各位同学大家好,在这个小节中,我们会学习进程间通信的几种方式,分别,是共享存储消息传递还有管道通信
一、什么是进程通信
进程之间的通信,指的就是两个或者多个进程之间,产生了数据交互,在一个系统当中,可能会同时存在多个呃进程,多个进程都在运行,那这些进程之间难免需要,相互配合着工作,在这种情况下,进程和进程之间的这种通信,数据通信就显得很有必要了,比如说当我们在玩微博的时候,可能你会看到一篇嗯,某明星的八卦对吧,一个吃瓜的文章,你想把这个文章分享给你的微信好友,那你是不是可以直接使用微博这个呃,呃这个应用里面内置的一个分享功能,然后把这个吃瓜文,分享给你的微信好友,那可以看到,在这个过程当中,其实就已经发生了,进程之间的通信了,本来这个吃瓜文的链接是在微博这的,然后你直接用微博的这个分享功能,直接就把这个呃吃瓜文的链接,分享到了微信这,所以这个过程显然是进程和进程之间,呃发生了这种数据交互,也就发生了通信,好说到这,大家也可以关注一下我的微博,王道咸鱼老师啊,当然也可以,关注一下我的这个微博小号,就是平时我我,我开那个变声器给大家讲啊,计算机网络的时候啊,我是以楼楼老师的这个,这个身份来示人的,好所以上面这个是我的大号,下面这个是我的小号啊,大家可以关注一下,好那既然我们进程之间的通信,是很有必要的,那么进程之间的通信应该如何实现呢,这个需要操作系统的支持,需要操作系统的支持,好那为了,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z3SUsEv1-1692438038890)(https://cdn.staticaly.com/gh/zben777/figures@main/img/202308111935057.png)]
二、为什么进程通信需要OS支持
呃探究这个问题,我们首先要聊清楚,为什么这个进程之间的通信,一定要有操作系统内核的支持,原因是这样的,我们系统当中,给各个进程分配啊,内存地址空间的时候啊,各个进程的这个内,内存地址空间是相互独立的,比如进程p它可以访问自己的空间,进程q可以访问自己的空间,但是进程p,它不可以访问进程q的地址空间,啊这么规定是出于安全的考虑,因为你想一下,如果一个进程,可以随意的访问其他,进程的这个内存地址空间,那么呃,一个进程是不是就可以随意修改,其他进程的数据了,或者随意的读取其他进程的数据,那这样的话你想想你的手机里边呃,不知道什么时候,安装了一个一个什么垃圾,软件对吧,然后这个垃圾软件这个垃圾软件,如果他可以随意的访问你的呃,其他进程的地址空间,那有可能他直接,把你微信里的一些私密的聊天数据,或者一些私密的呃,什么照片之类的直接就给你读走了,对吧,那这显然是很很危险的不安全的,因此呃出于这种安全的考虑,各个进程,只能访问自己的这一篇内存地址空间,而不能访问其他进程的内存地址空间,无论是读或者写数据都不行,好因此如果两个进程p和q,他们之间需要进行数据交互,需要进行进程之间的通信,那么显然,进程p是不可能,直接把这个数据写到,q的这片空间里边的,好所以,由于进程,不可以直接访问其他进程的这个空间,因此就必须要有操作系统的支持,才可以完成进程之间的通信,才可以完成进程之间的通信,好那嗯,我们接下来会介绍,三种进程之间的通信方式,分别是共享存储,消息传递还有管道通信,首先我们来看共享存储这种啊进,
三、共享存储
进程间通信的机制,共享存储的原理是这样的,各个进程只能访问自己的这片空间,但是如果,操作系统支持共享存储的这种,啊这种功能的话,那么一个进程,它可以申请一片共享存储区,而这片共享存储区,也可以被其他进程所共享,这样的话,一个进程p,如果他要给q传送数据的话,那么p是不是就可以先把数据写到,这一篇共享存储区里面,因为他对这片区域是有访问权限的,然后接下来,进程q再从这片区域里边读出数据,读数据是不是就OK了,好所以,由于这个共享存储区可以被,多个进程所共享,因此这些进程之间的数据交换,就可以通过这一片,被共享的区域来进行,那这就是共享存储的,呃进程间通信方式,比如像Linux操作系统当中,大家可以去呃上网搜一下,呃如何实现共享存储呢,首先呃一个进程比如说进程p,和q他们想要通信,那么发起通信的这个进程p,他可以使用Sham memory open,使用这个系统调用,来申请一片共享内存区,也就黄色的这片区,好接下来,进程p和进程q都需要使用m map,使用这个系统调用,把这一片存储区域,映射到自己的虚拟地址空间当中,现在,大家还不知道什么叫虚拟地址空间,等大家学到第3章的时候,再回头看这个部分,可能会更清晰一些,如果用第三张,我们要学习的内容来解释的话,相当于调用了m map这个函数之后,进程的页表项或者段表项,就会增加一项,然后这个页面或者这个段,就可以映射到,就可以映射到,刚才申请的这一篇共享存储区,那这样的话,各个进程的虚拟地址空间当中,都包含了这个共享存储区,他们都可以访问这一篇共享存储区,那这个部分大家学到第三章之后,再回来看,可能会更清晰一些,总之只需要简单的加一个页表像,或者段表像,就可以完成这种共享内存区的映射,这个事情了,另外还需要注意一个问题,如果多个进程都往这片区域,写数据的话,是不是有可能会导致写冲突啊,比如进程p他正在往这片区域写,那进程q也往这一片写,那是不是就有可能导致,数据覆盖的问题啊,好所以,各个进程,他们之间,如果使用共享存储的方式,来进行通信的话,那么需要保证,各个进程对这个共享存储区,的访问是互斥的,应该保证他们对这片区域的访问,是互制的,也就是,当进城p正在访问这片区域的时候,那其他进城就不能访问这片区域,那怎么实现这个互斥的功能呢,操作系统内核会提供一些同步互斥,工具比如说我们在2.3那个部分,2.3那个部分会学习PV操作,PV操作就是操作系统,会提供的这种同步互斥的工具,所以呃各个进程,各个进程,他们可以用类似于PV操作这种机制,来实现,对呃共享存储区的一个互斥的访问,那具体的,大家可以学了2.3那个小节之后,再回头来理解这句话,好总之,各个进程对共享存储区的访问,应该是互斥的,进行的好,这是共享存储,刚才我们说的这种共享存储的方案,是基于存储区的共享,就是操作系统给你划定,
了这么大的一片区域,比如说这一这整片是4KB,4KB这么大,好那这么大的区域当中,几个进程,你到底要往这个地方写,还是要往这个地方写,或者读的进程你要从这个地方读,还是从另一个地方读,这些都是很很自由的很自由的,操作系统只负责把这片区域划给你,但是并不管你怎么使用这片区域,这是基于存储区的功效,操作系统划分出这一片共享区域之后,数据你到底要怎么存,到底要存在什么位置,都是由呃要通信的这些进程,他们之间来来决定的,而不是由操作系统来决定,所以这种共享方式他灵活性非常高,是一种高级通信方式,就是传送数据的速度会很快,好相比之下,还有一种方式,叫做基于数据结构的共享,比如说操作系统给你们两个进程,划定的这篇共享区域,它就规定,只能存放一个长度为10的数组啊,大家可以理解为是一个特,殊的全局变量,就是这个特殊的全局变量,可以被各个进程所共享,为什么叫特殊的呢,因为如果我们写代码的时候,定义的全局变量,其实是局部于一个进程的啊,而这个地方我们所谓特殊的全局变量,是可以被各个进程所共享的,但是当我们定义这个全局变量的时候,比如说,我们是定义了一个int型的数组,int a长度为3,好那各个进程来共享这个嗯,这个这个数据结构,这个长度为3的呃数组的时候,各个进程对这一片共享区域的访问,读和写是不是就只能按照,这个数据结构所规定的,这种格式来进行了,只有三个int型的变量,每一次要么读,要么写一个int型的变量,好所以可以看到,如果是基于数据结构的这种共享的话,那这个进程之间,他们之间通信是不是自由度就是呃,没有那么高,并且这个传送数据的数,呃速度也会比较慢,所以基于数据结构的这种共享方式,是一种低级的通行方式,低级的通行方式好,那这就是进程之间通信的第一种方法,叫做共享存储,共享存储又可以进一步划分为,基于数据结构,的共享和基于存储区的共享,上面这种共享方式灵活性差速度慢,下面这种共享方式灵活性高速度快,好接下来看第二,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2MR5lLbO-1692438038891)(C:\Users\ZhangBen\AppData\Roaming\Typora\typora-user-images\image-20230811193645576.png)]
四、消息传递
第二种进程之间的通信方式,叫做消息传递,如果采用这种方式的话,那么进程之间的数据交换,会以格式化的消息为单位,通过操作系统提供的发送和接收,这样的两个原语来进行数据交换,一会我们会用,动画的方式带大家来理解这个过程,而什么叫格式化的消息呢,先来看这个,所以格式化的消息由两个部分组成,一个是消息头,一个是消息体,那消息头要写明要注明,这个消息这一枕头消息,到底是由谁发送的,到底要发送给谁,然后整个消息的长度是多少等等,就是一些概要的信息,这是消息头,然后消息体里边呢就是啊具体的,一个进程,要传送给另一个进程的这个数据,好那么呃,这种消息传递的进程之间通信方式,又可以进一步的划分为,直接通信方式和,间接通信方式,其中直接通信方式就是呃,发送进程要指明接收进程的ID,我们系统里的每一个进程都会有一个,进程的id,p i d嘛那发送的进程需要指明,到底是谁来接受,所以直接通信方式相当于,我发送进程直接点名,我就是要他接受,就这个意思,而间接通信方式呢,会通过一个叫做信箱的啊,一个中间实体,来进行通信,所以间接通信方式又称为信箱通信,方式好,我们来看一下这两种啊,消息传递的这种通信方式的区别,首先来看什么是直接通信方式
1、直接通信方式
进程p现在要给进程q发送一个消息,那么在操作系统的内核区域,操作系统的内核区域,是不是管理着各个进程的PCB啊,进程控制快,这是由操作系统来管理的呃数据结构,好那在各个进程的这个PCB当中,有一个呃包含了一个队列,叫做消息队列,消息队列,比如说进程q的PCB当中,其中就包含了一个进程q的消息队列,也就是呃其他进程,其他进程要发送给进程q,应该被进程q接收的这些消息,这些消息,都挂在啊进城q的这个消息对列里面,好那来看一下现在故事是这样的,进城p要给进城q发一个消息,那首先进城p需要在自己的地盘,自己的这片地址空间这,来啊来完善这个消息的信息,包括消息头消息体,接下来进程p,进程p它会,使用到刚才我们说的这个发送源语,操作系统提供的发送源语啊send,用这个原语来指明我的这个message,这个消息是要发送给q,这个进程指明了这个消息的接收者,指明了消息的接收者,好,那这个发送原语会导致操作系统内核,接收到这个消息,并且会把刚才的这个消息,把它挂到进城q的消息堆列里边,也就是说这个消息,体这个消息体,是从进城p的这个空间进城p的啊,用户空间被复制到了内核空间,被复制到了内核空间,好接下来,接下来如果进程q啊开始运行,那进程q,它可以使用接收源语receive来指明,我现在要接收一个message,接收一个消息,那接收呃谁发来的message呢,是接收p进程发来的message,所以这个接收源语这儿,它需要指明我要接收的这个,呃这个这个消息是来自于哪个进程,好所以进程q执行这个接收源语之后,操作系统内核,会检查进程q的这一系这些消息,对列看一下哎,这几个消息,到底哪个消息是由p发过来的,好现在找到了邮p发过来的消息,那么,操作系统内核会把这个消息体的数据,又从呃操作系统的内核区,给复制到,给复制到这个进程q的这个用户区,这个地址空间这儿,好所以所谓的直接通信方式,直接通信方式就是,要点名道姓的来进行这个消息传递,我一个进程到底是要传给谁,然后接收的这个进程啊,他接收的时候,我要接收的是来自于谁的那个消息,需要点名道姓的进行这个消息传递,好这是直接通信方式,接下来我们再来看什么叫间
2、间接通信方式
接通信方式,刚才我们说间接通信方式呃,他需要通过一个中间实体,所谓的信相来进行消息的传递,所以又称之为呃信相通信方式,好那这种通信方式是这么来实现的,比如进程p和进程q他们之间要通信,那么进程p可以通过系统调用,可以通过系统调用申请一个邮箱,一个所谓的邮箱,比如说,他可以向操作系统申请一个新的邮箱,这个邮箱的名字叫做a,叫做a当然也可以申请多个邮箱啊,比如说另一个邮箱叫做b,好现在这两个进程怎么通信呢,进程p,首先它在自己的这个地址空间这,嗯来来完善这个消息体的内容,在自己的地址空间内来,来填充这个消息的内容,呃这个过程大家理解吗,其实就相当于你写这进程p的代码啊,你定义了一个变量叫message,然后message到底要等于多少,你给它付一个值,这就是所谓的在自己的地址空间内,在自己的地址空间内,完善这个消息题的信息,其实就就是一个复值,就是一个复值这个意思,好现在,进程p,他已经给啊他要发送的这个消息,这个消息体已经付好值了,那么进程p可以用发送元语send,来指明我要发送到哪个信箱,指明我要发送到的是a信箱,然后发送的是message这个消息题,好注意哈,这个间接通信方式,是指明了我要发送到哪个信箱,是要发送到a信箱,并没有指明我要发送给哪个京城,刚才我们说的直接通信方式,直接通信方式是指明了,点名道姓的,指明了我是要发给q这个进程的,这是直接通信方式,但现在我们的这间接通信方式,也就是信箱通信方式,我并没有指名道姓的说我要发给q,我只是,指明了我要发送到a这个邮箱这儿,好那进程q,进程q它使用接收原语的时候,它可以指明我是要从a这个信箱这儿,接收一个message,接收一个消息体,那这样的话,信箱a的这个这个这个消息message,就会被操作系统复制给复制到这个,呃进程q的,自己的这个空间这了,好所以,这就是,使用信箱来完成消息传递的一个过程,那通常来说,操作系统是可以允许,多个进程往同一个信箱里,就是发消息,也允许多个进程从同一个信箱里啊,就receive就是接收消息,好,那这是消息传递里边的间接通信方式,又叫信箱通信方式,注意体会,和之前直接通信方式的一个区别,直接通信方式需要点名道姓的指名,我是谁我要发给谁,好接下来我们再来看最后一种
五、管道通信
进程之间的通信方式叫做管道通信,那管道这个词还是很形象的,它就像我们的一个水管,水管的管道一样,就是呃写进程,写进程可以从水管的一边写入数据,读进程,从水管的另一边就是取走数据,这个数据的流动只能是单向的,就从左到右或者从右到左,只能是单向的,就像水管当中的水流一样,这个水流的方向只可能是单向的对吧,要么从左到右,要么从右,到左大家有没有见过一个水管里边,那个水流既往右同时又往左的水流吧,没有见过这样的水管对吧,好所以管道通信的,这个管道和水管是一样的啊,我们可以从一端写入数据,从另一端读出数据,这个数据的流向指呢,是单向的而不可以是双向同时进行的,好那站在操作系统的层面,这我们提到的管道,它是一种特殊的共享文件,又叫pipe文件,pipe就是英文的水管的意思嘛,管道的意思,也就是说如果两个进程,他们之间,要用管道通信的方式,进行这个进程间通信,那么首先我们需要通过这个呃,系统调用的方式,就某一个进程通过系统调用的方式,来申请一个管道文件,操作系统会新建这个管道文件,这个文件的本质,其实就是在内存当中,开辟了一个大小固定的内存缓冲区,然后两个进程,可以往这个内存缓冲区里边,写数据和读数据,但是这个数据的读写是呃先进先出的,先进先出有这样的特性呃,去年有很多同学,在这个地方是有疑问的哈,就是一个管道,一个管道文件,本质上是一个大小固定的内存,呃内存区域,那这不和我们那个共享内存的方式,就没有什么区别了吗,刚才我们说,就是之前我们说共享内存的那种呃,通信方式,也是操作系统给两个进程,给两个进程p和q,给他们分配了一片可以共享,可以被共享访问的内存区,对吧而现在我们的这个管道,我们这个管道也,是一个大小固定的内存区域,也是可以被两个进程p和q来访问的,那和我们共享内存有什么区别呢,有什么区别呢,好区别在这啊,在共享内存的这种通信方式当中,我们刚才说过,这一片内存区域p和q你想怎么,你想怎么玩就怎么玩,你想把数据写在这写在这写在这,都OK没有问题,然后你想从这读数据,想从这读数据都OK,没问题没有任何的限制,很自由这是共享存储的通信方式啊,没有任何的限制,但是管道通信的这种方式哈,管道通信的这种方式,嗯相当于是这样的,这操作系统,给两个进程分配了一个内存缓冲区,也就是一个管道文件,也就是一个管道文件,好现在p,可以往这个管道文件里边写数据,然后q,是要从这个管道文件里边读数据,那呃,什么叫先进先出的特性呢,可以这么理解,这个区域他大小肯定也是有限的对吧,好现在p往里边写,那么如果他的头部这头部这是空的,那么他先往这写,写写写一个字节,比如说一个字节的数据,然后这写了之后再再往这写,然后再往这写,再往这写,好对于q来说他要取走数据的时候,并不是说他想读哪,他想读哪就读哪,他想取哪就取哪,他只能先把头部,头部的这些数据给取了,直接取了,依次的往后取,明白我意思吧,就是在共享存储的那个通信方式里边,我可以我可以把我的数据写在中间,这直接就写在中间,这虽然前面有空的但我直接写在中间,这或者我直接写在尾部这都是OK的,没有任何限制,然后我这个读进程,读数据的时候也是一样,我可以直接从中间取数据,或者直接从尾部取数据都是OK的,但是在这个管道通信里边,在管道通信里边,它是一个数据流的形式,我这个数据如果前边还有空位的话,这个数据肯定是先放在前面这个位置,放在前面这个位置只有前面填满了,只有前面填满了,我才会往继续往后面写这个数据,而读数据的时候也是一样的,只能先把前边的这些数据读空了,然后才可以读后续的这些数据,才可以读获取的这些数据,好所以管道通信和这个呃,和这个共享内存的通信嗯,区别还是很大的,管道通信就要求这个数据的就是读写,一定是先进先出的,一定是先进先出的,就是一个对列嘛,或者更准确的讲,我们应该把这个管道管道的这个呃,内存缓冲区这一小片内存缓冲区,把它理解为一个循环对列,一个循环对列,现在大家应该都学过呃数据结构了,循环对列的原理我们知道对吧,就循环对列的话呃如果说如果说这个,它嗯整片区域后半部分满了,后半部分就是p,嗯它写入数据,然后后边的这些位置都写满了,但是前边这些位置如果空出来的话,如果空出来的话,那是不是p,就可以往这个,循环对列的另外这个空的这一边,继续写入数,据啊去写数据,好所以,这个固定大小的内存缓冲区,本质上就是一个循环对列,而写进程往里边写数据,或者读进程从里面读数据,都需要,遵循这个对列的先进先出的一个规则,这就是管道的这个内存缓冲区,和我们刚才提到的,共享存储的这个共享内存区,的一个区别,一个是没有限制的,一个是先进先出这种限制的,好那刚才我们还提过一个点呃,用管道通信的这种方式,一个管道的数据流向一定是单向的,而不可以是双向的,所以一个管道它只能支持半双公通信,也就是在某一段时间内,只能实现这种单向的传输,那如果说两个进程我需要给你传,同时你也需要给我传,就是两个方向的数据传输,都需要同时进行的话,嗯我们称这种,双向同时进行的数据传输为双宫,全双宫通信,全双公通性,这些是既往的一个概念哈,半双公通性指的就是,同一时刻我只能支持单向的传输,但是这个方向的传输结束之后,我也可以把这个传输的方向改过来,但是两个方向的传输不可以同时进行,这是半双公通信,而全双公通信,指的是,两个方向的数据传输都要同时进行,好所以,如果,需要两个方向的传输都同时进行的话,那么这种情况下,我们就需要申请,向操作系统申请两个管道文件,一个管道文件呃,负责从左往右的这个数据传输,另一个管道文件,负责从右往左的这个数据传输好,另外各个进程对管道,的访问也应该是互斥的进行的,应该是互斥的进行的,但是呢对管道的互斥访问,是由操作系统来保证的,不需要由这个进程自己来保证,好第三点需要注意的是,刚才我们说,这个管道,它是一个大小固定的内存缓冲区,既然大小固定,那么这片缓冲区肯定会被写满对吧,那如果写满的话,这个进程是不是就不能,继续往里面写数据了,好所以如果管道被写满的话,那么写进程写进程应该被阻塞,他写数据的这个这个动作应该被阻塞,等待,直到读进程把管道里边的数据取走,等这个管道有空位了,我们再把这个写进程给唤醒,好另一个方面,读进程是从这个,这个呃内存缓冲区里面读数据的,那同样的这个数据有可能会被读空,对吧所以如果管道被读空的话,那么读进程的读read这个动作,就应该被阻塞,直到写进程往这个管道里边写入数据,才可以把这个读进程给唤醒,所以管道通信的这种方式,不管是读进程还是写进程,都有可能进入阻塞的状态,好接下来第5点,也是我们管道通信这个部分,很多教材最有争议的一个点,管道通信的实现方式,决定了,管道当中的这些数据一旦被读出,就彻底的消失了,就彻底的消失了,所以如果如果说有多个读进程,有多个读进程同时读一个管道的时候,就有可能会导致错乱,导致混乱,因为我们管道里边的这些数据,并没有指明说我到底是要给进程q,的还是要给进程进程m的,没有说明对吧,所以如果多个进程,如果多个进程,嗯都从同一个管道这读数据的话,那么有可能有可能呃,这个数据的读取,这个动作就是就是会比较乱的,第一块数据可能被m读走了,然后第二块数据可能被q读走了,那针对于这个问题,不同的操作系统会有不同的解决方案,比如说像早期的system five,这种操作系统,它在实现管道的时候就规定一个管道,一个管道允许多个写进程,多个进程同时往这个呃管道里面写,写就完了,但是呢读进程只允许有一个,只允许有一个,不允许多个读进程同时读这个管道,那我们2014年的有个408真题当中,高等教育出版社的那个官方答案,也是这么说的,就是他说一个管道可以有多个写进程,一个读进程,这是高等教育出版社啊官方给的答案,但是在有的操作系统当中,比如说Linux里边,Linux里边,呃又允许有多个写进程和多个读进程,只不过系统会让各个读进程,轮流的从管道当中读数据,比如说有两个进程q和m,进程q和进程m,都需要从这个管道里面读数据啊,那么q和m就是轮流着读的,你读一次我读一次你读一次我读一次,由操作,系统来控制这个轮流读数据的过程,所以在很多操作系统的教材里面,大家又有可能会看到说,一个管道可以被多个进程写,多个进程读,而在有的操作系统教材里面,他又会说一个管道允许多个进程写,但是只允许一个进程读,因此这个地方也是去年和前年,争议非常非常大,很多同学都不知道该信谁的呃,一个一个地方,好因此这个地方我们要知道,在实际应用当中,一个管道是可以被允许多个写进程,多个读进程的,但是我们毕竟最终是要面对考试,而考试呢,嗯这种应试类的这种考试,肯定都得有一个所谓的标准答案对吧,那以后以后大家在呃,讨论这个管道通信的时候,我们都和这个高教社呃,14年的这个真题统一就说,可以有多个写进程,然后只能有一个读进程,我们以这种说法为准,同时大家在做题的时候,如果看到有的题目说,一个管道可以有多个写进程,多个读进程,也不要觉得奇怪,从现实应用的角度来看,这种说法并没有什么错误,好,那这就是最后一种进程间通信的方式,管道通信那在
六、总结
在这个小节中,我们介绍了共享存储,消息传递和管道通信,这三种常见的进程间通信方式,那这三种呃通信的功能,都是需要操作系统的底层来支持的,共享存储的这种通信方式意味着啊,操作系统会分配一个共享内存去,并且把这个共享内存去映射到,各个进程的虚拟地址空间当中,那这个地方现在大家还暂时看不懂,等我们学到第3章,知道什么是断表,什么是页表之后再回来看这块,你就会恍然大悟了,要把一片内存区域映射到进程的,虚拟地址空间当中,只需要加一个段表象就可以做到,非常简单,另外呢呃,采用共享存储的时候,需要注意各个进程呃,我们需要保证,他们是互斥的访问这个共享,共享空间的,而这个互斥的过程需要有呃通信进程,就是各个通信的进程,他们自己来负责实现,比如说,使用操作系统提供的PV操作等等,使用操作系统的呃同步互斥的机制,来确保,各个进程是互斥的访问这片区域的,其实本质上对于共享存储区域的访问,是一个读者携手问题,这个是我们在2.3,2.3那个小节里边会学的,一个经典的同步互助问题,读者写着问题,也就是说多个进程啊,可以同时从这片区域里读,但是不可以同时往这片区域里边写,等大家学到读者写这个问题的时候,会知道我这说的是什么,怎么回事,好接下来第二种进程间通信的方式,叫做消息传递,消息传递又可以进一步分为,直接通信和,间接通信方式,直接通信方式就是呃,要指名道姓的说明,我要把这个消息发送给哪个进程,然后呃,操作系统会把这个消息直接挂到,接收进程的消息堆列里面,这是直接通信方式,间接通信方式又叫信箱通信啊,消息会被,操作系统先放到一个指定的信箱当中,而消息的接收者,也需要指明自己要从哪个信箱当中,取走一个消息,那这个小节最后,我们又介绍了管道通信,对于操作系,统而言管道通信的这个管道,其实是一个特殊的共享文件啊,你在Linux里边采用呃管道通信的话,你是可以在自己的系统里面,找到这个文件的,但本质上,这个文件它就是一个内存缓冲区,如果结合,我们数据结构的知识来看的话,这个内存缓冲区,其实就是一个循环对列,一个循环对列,写进程可以往这个循环对列里边呃写,写一些数据,然后当这个内存缓冲区,这个循环对列满了之后,写进程需要阻塞,那读进程读的时候啊也是一样的,如果说整个内存缓冲区,或者说这个这个循环队列被读空了,那么读进程就需要阻塞等待,那需要注意的是,一个管道文件只能实现半双弓的通行,这就类似于我们现实生活中的水管,一根水管啊我可以让水从左往右流,然后也可以让水从右往左流,但是我不可能让这个水管里面的水,既往左流也往右流,所以如果我想要,从左往右和从右往左的这个水流,同时都存在的话,那么我就需要建立两个管道,两个水管才可以实现,好的,那么这就是进程间通信的三种方式啊,那最后,再跟大家说一个王道书上的小问题,这个小问题也是,去年和前年让无数人抓狂啊,不知道他说的对不对的一个地方啊,今年我查阅了大量的资料,并且自己也在Linux操作系统上,就是做了广道通信的一个实验,那么,现在我有一个很笃定的一个答案,可以告诉大家,呃王道书里大家看一,下哈你们王道书里有这样的一句话,就是说,呃,写进程会先把这个管道缓冲区给写满,然后才让读进程读,当缓冲区中还有数据时,写进程不会往缓冲区里边写数据,这句话是错误的,这句话是错误的,这句话读起来就像是说,你一个管道必须全部写满了之后,读进程才可以从,才可以把这个管道里的数据取走,但事实上不是这样的,我在Linux上面呃做了这个实验,验证了这个问题,当我们的写进程,往管道里边写数据的时候,即便管道没有被写满,也可以被读进程给读,呃给读走,就是读进程要读这些数据,只有一个条件,就是管道别空了,只要管道没空,那么读进程就可以,继续的从这个管道里面读数据,对于写进程也是一样的,我不管你这个管道有没有被堵空,反正只要管道没满,只要管道没满还有空间可以让我写,那么我就可以继续往管道里面写数据,这是我做实验验证过的东西,好所以大家把那个呃,王道书上的这句话给修改一下,这段话是说的有问题的,好的那么这就是这个,,
No.5 线程的概念与特点
各位同学大家好,在这个小节中,我们会学习现成,相关的一系列的知识点,首先我们会用一个例子来介绍,什么是现成,为什么要引入现成机制呢,在引入现成机制之后,呃比起传统的进程机制来说,带来了哪些变化,之后我们会介绍县城,有哪些重要的属性,首先来看一下什么是县城,
一、什么是线程为什么要引入线程呢
为什么要引入县城呢,在很久很久以前啊,在没有引入进程之前,系统之间的各个程序,是只能创行执行的,所以在那个时候我比如说像我,我们想一边运行啊音乐播放程序,一边运行QQ这个程序,那么啊显然是不可以实现的,在那个时候我们不可能边聊QQ,然后边听音乐,但之后引入了进程的机制之后,就可以实现,QQ边聊QQ边听音乐这样的事情,但是大家再来呃深入的思考一下,QQ可以做一些什么事情呢,我们可以用QQ进行视频聊天,同时还可以和其他的人进行文字聊天,然后再同时还在传送呃文件,那么这些事情,是怎么在进程当中完成的呢,很显然在传统的进程定义当中,进程它是程序的一次执行,但是这些功能,视频聊天,文字聊天,传送文件这些功能,显然是不可能由一个程序,顺序执行来处理的,如果只能顺序的来处理那么就不可,能呃在我们用户看来,这几件事情是可以同时发生的,就不可能有这样的现象,所以,有的进程,其实他是需要同时处理很多事情的,就像刚才咱们说的QQ那样,但是传统的进程,他只能串行的执行一系列的程序代码,就是这个样子,在传统的进程呃机制当中,CPU会轮流的为各个进程进行服务,那么这些进程就可以并发的执行,并且每一个进程,会有他自己相应的一系列程序代码,然后被CPU服务的时候,这些代码就可以一句一句,开始往下执行,所以在传统的进程机制当中,进程是执行由的最小单位,这句话什么意思呢,听了后面的呃这个讲解,大家应该就可以理解,之后为了,满足,像咱刚才咱们说的一个进程当中,同时就宏观上同时做很多事情,人们又引入了现成机制,用来增加系统的并发度,引入了现成之后,系统的呃CPU的这个,调度服务对象就不再是进程,而是进程当中的线程,每一个进程当中可能会包含多个线程,然后CPU会轮流的为用一定的算法呃,轮流的为这些线程进行服务,就像这个样子,为各个县城服务,那么这样的话,同一个进程当中被分为了多个县城,像刚才咱们说的QQ,视频聊天和传送文件,这些这两件事情,如果想要并发的执行的话,那么我们就可以把,这两件事情对应的处理程序,放到两个呃,不同的县城下,那么这两个县城可以并发的执行,自然这两件,事就可以并发的完成,所以在引入了县城机制之后,县城就成了程序执行流的最小单位,在没有引入县城之前,一个进城其实就对应一份代码,这些代码只能顺序的依次往下执行,但是在引入了县城之后,每每一个进程可以有多个线程,并且,这些线程它可以有各自不同的代码,也可以是每个进也可以是不同的进,线程运行的是同一份代码,但是这些代码都会并发的被CPU处理,然后并发的依次执行下去,所以这就是呃,所谓程序执行流的最小单位的意思,所谓的县城其实我们可以把它理解,
也为是一种轻量级的进程,以前CPU调度的单位是进程,但是现在CPU的服务对象不是进程,而是以线程为单位,所以线程它是基本的CPU执行单元,也是程序执行流的最小单位,这个经过刚才的讲解,相信大家已经可以理解,在引入县城之后,进城之间可以并发的执行,并且进城之间的各个呃,县城也可以并发的执行,所以引入县城机制,进一步的提高了系统的并发度,可以使得一个进城内,也可以并发的处理各种各样的任务,就像刚才咱们聊到的QQ聊天,呃什么传文件这样这些事情,然后在隐若县城之后,晋城不再是CPU调度的基本单位,晋城它只作为,除了CPU之外的系统资源的分配单元,什么意思呢,假如系统当中,那假如说这个计算机系统,当中有各种各样的系统资源,那么这些资源是被分配给晋城的,而不是分配给县城,就像这个样子,那么在引入了现成机制之后比
二、引入线程后的变化
起传统的呃进程机制来说,有了哪些变化呢,首先我们来看一下资源分配,和处理机调度方向,这个刚才已经讲过,传统的晋城机制当中,晋城他既是资源分配的基本单位,也是处理机调度的基本单位,但是在引入县城之后,晋城他只是资源分配的基本单位,而县城变成了调度的基本单位,这是区别,在并发性角度来讲,传统的进程机制中,进只能是进程之间并发的执行,但是在引入县城之后,各个县城间也可以并发执行,所以进一步提升了系统的并发度,在实现并发带来的系统开销方面,传统的进程间并发,需要切换进程的运行环境,切换进程的运行环境,其实系统开销是比较大的,但是呃引入了县城机制之后,如果我们是切换,同一个进城内的不同县城,那么我们不需要切换呃,进城的运行环境,这样的话,呃并发所带来的系统开销,就会进一步的降低,怎么理解,切换进程的运行环境,所带来的系统开销呢,我们来用一个,呃去图书馆看书的例子来来理解,假如说,你在使用图书馆当中的某一张桌子,但是突然有一个人,你不认识的人也要用这个桌子,那么你需要把你的运行环境,你的书给收走,然后他要把自己的运行环境把他,自己的书放到桌子上,所以这就是呃,进程切换所带来的运行环境的切换,这个切换过程,其实需要付出一定代价的,你需要把书搬走他需要把书放放上去,但是如果说呃,这个时候是你的舍友,想要用这张书桌的话,那么既然你们认识,就相当于你们俩是属于同一个顶层的,这种情况下就可以不把你自己的书,桌子呃不把你自己的书收走,把这个书依然放在桌子上,这就类似于统一进程内的现程的切换,统一进程内的现程切换,不需要切换进程的运行环境,所以由于你们不需要把书挪来挪去,因此这个开销也会降低很多,接下来我们再来看一下静止现场,
三、线程的属性
程有哪些属性,线程是处理机调度的单位,这个刚才已经强调过很多次了,然后多个CPU计算,多CPU的计算机当中,就是多核CPU的计算机当中,每个线程它可以占用不同的CPU,比如说现在的呃,CPU一般都是什么双核4核8核的,那各个线程可以分配到不同的,核心里去,另外呢,每个线程它其实像呃会有一个线程ID,和线程控制快,TCB这样的数据结构,线程控制快,其实呃有点类似于我们之前学过的PCB,进程控制快,线程控制快也是用于管理线程,所创建的一个数据结构,那么和进程类似,线程他也会有就色,就绪阻塞运行这样的三种基本状态,因为隐若县城机制之后,县城他只是处理机调度的基本单位,而系统资源分配是分配给晋城的,所以县城几乎不拥有系统资源,系统资源都是在晋城那里,那么县城,肯定也需要使用一系列的系统资源,这些系统资源从哪里来呢,其实同一个进程当中的不同县城,他们是可以共享,使用这个进程所拥有的,系统资源的,这些系统资源包括像什么IO设备,还有内存地址空间这样的资源,由于呃同一个进程当中的不同县城,他们可以共享内存地址空间,所以同一个进程中的县城,他们之间的通信,就可以不需要呃操作系统干预,可以直接通过共享的内存地址空间,就可以完成他们之间的信息传递,另外呢我们还需要注意,同一个进程中的线程切换,其实并不会引起进程切换,但是不同的进程中的线程切换,会引起进程切换,如果我们切换的是同进程内的线程,那么由于不需要切换进程的运行环境,所以系统开销是比较小的,如果我们切换的是不同进程间的线程,那么它会导致呃进程的切换,相应的也需要切换进程的运行环境,所以系统开销就比较大,这个就是刚才咱们讲到的图书,馆那个例子,好的那么这就是线程的相应的一系列
No.6 线程的实现方式和多线程模型
各位同学大家好,在上个小节中,我们学习了现成相关的一些基本概念,基础的知识,那这个小节中我们会来看一,下有哪几种啊,现成的实现方式,并且会学习几种多现成模型,那现成的实现方式分为用户级现成,和内合级现成,另外还有的系统当中,会把这两种实现方式都混合起来使用,那这个大家一会会看到实际的例子,那首先我们来看一下,第一种现成的实现方式叫
一、用户级线程
叫做用户级现成,其实这种实现方式,是在早期的操作系统,也就是只支持进程,还暂时没有支持,现成的那些操作系统当中,来使用的,当时所谓的线程,是由程序员们写的线程库来实现的,也就是说在这个时代,操作系统的视角,看到的其实依然是只有进程,但是程序员们写的这些应用程序当中,可以使用线程库,来实现多个线程并发的运行,这样的事情,我们还是来结合,上,小节当中提到的这个例子来进行理解,上个小节中我们提到过,我们的QQ可以一边视频聊天,一边文字聊天,一边实现文文件传输,那上个小节中我们提出了这样的方案,如果要让这三个事情并发的运行的话,那么在不支持现成的系统当中,我们可以分别建立三个进程,这三个进程分别是处理其中的某一个,呃事情进程一的代码,是不断不断的来处理视频聊天,这个事情,进程2是不断不断的来处理,这个文字聊天,而进程3是处理这个文件传输,那我们可以看到,处理视频聊天的这个代码,呃是在是用这个循环来一遍一遍,一遍的呃不断的执行的,另外的两个代码也一样,所以其实我们可以用这样的方式,来实现让这三段代码并发的运行,我们用一个外物循环,让它一直不断的循环,然后这个i的值会012012,这样循环的变化,当i等于0的时候,我们可以让这个进程来处理视频聊天,当i等于一的时候让他处理文字聊天,当i等于2的时候让他处理文件传输,那由于我们这个程序啊,进行外循环的速度是非常快的,那我们其实也可以把这3段代码,看作是3段呃,并发的运行的代码,他们分别处理了不同的事情,所以其实如果我们从,单纯代码的角度来看的话,那么一个线程,其实我们可以把它理解为,是一段代码逻辑,那这个地方提到的这三段代码逻辑,我们就可以把它看作是三个线程,另外,我们这写的外物循环的这个处理逻辑,其实我们就可以把它看成一个,最简陋最弱智的一个线程库,这个县城库,完成了对各个县城的一个管理,调度的工作,那这个弱,那这个弱智县城库,对我们的这些县城的调度规则很简单,就是第一次先处理视频,第二次处理文字,第三次处理文件,第四次要处理视频,第五次处理文字等等等等,这个地方,我们用一个简单的wild循环,和几个if语句,就实现了一个最简单,最简单最简单的现成库,那我们很多的编程语言都会提供啊,用于管理现成的现成库不,过他们提供的现成库,要比我们的wild循环复杂多了,程序员可以利用这个现成库,来实现这个用户及现成的创建,销毁调度等等一系列的功能,那接下来问题来了,在刚才我们所说的这个例子当中,操作系统其实他只看得到进程,而这个进程上处理机运行的时候,其实是程序员自己写了一个线程库,来创建了逻辑上的线程,也就是这所谓的用户级现成,那我们来思考这样的几个问题,第一这些用户级现成的管理工作,是由谁来完成的,其实我们刚才写的这个wild循环,就是简单的实现了对这三个,现成的管理,让他们交替的运行,所以用户级现成的管理工作,是由应用程序通过现成库来完成的,并不是操作系统负责的,第二个问题,现成切换是否需要CPU,从用户态转换为内核态,那经过刚才的分析,这个问题其实也不难回答,我们的现成切换,其实是由我们这个外物循环来控制的,这并不需要呃,涉及到请求操作系统服务之类的事情,所以现成切换的管理,是由我们的现成库,应用程序自己完成的,在用户太下就可以完成,现成的切换工作,并不需要操作系统的干涉,第三个问题,操作系统是否能意识到用户,及现成的存在,那显然,操作系统他只能看到这个进程的存在,他只知道这个进程他是一坨代码,而在这坨代码里面,又分别被分为了几个现成,操作系统是,意识不到这些现成的存在的,所以,这也是为什么这种现成的实现方式,叫做用户及现成的原因,只有用户,才能感知到这个用户及现成的存在,而操作系统其实感知不到这些用户及,现成的存在,那最后我们要思考的问题是,这种实现方式它有什么优点和缺点呢,首先来看优点,刚才我们提到过,用户级现成的管理工作,包括切换创建等等,这些工作都不需要请求操作,系统的服务,只需要在用户态下就可以完成,也就是说对用户级现成的管理,并不需要涉及到CPU变态这个事情,而之前我们说过,CPU变态是有开销有成本的,所以那既然用户及现成的管理工作,不需要呃,CPU切换到内核态,所以对于他们的管理工作,肯定开销是比较小,效率是比较高的,那接下来来看一下,用户级现成这种实现方式有什么缺点,那我们回到我们自己实现的,这3个最简单的,用户级现成,我们来看一下,假设此时这个QQ进程上处理机运行,而这次运行的时候爱的值是等于0的,也就是说,视频聊天的,呃这一段代码会上处理机运行,但是假设,视频聊天的这段代码在运行的过程中,发生了阻塞,比如说他想要申请摄像头那个资源,但是申请失败,那么由于他,想要的这个系统资源得不到满足,因此这段代码的执行就会被阻塞,那我们想一下,既然,这个代码的执行被阻塞在了这个地方,那么这个外恶循环还能继续下去吗,肯定不行了对吧,只有这个阻塞被解除之后,这个外恶循环才可以继续啊执行下去,所以这种用户及现成的实现方式,有一个很明显的缺点,那就是如果其中的某一个现成被阻塞,那么其他的这些现成也会被阻塞,也没办法执行下去,那从这段尾代码当中,相信不难理解这一点,所以,这就是用户及现成这种实现方式,最大的一个缺点,只要其中一个被阻塞,那整个进程都会被阻塞,所以这种方式的并发度并不高,另外虽然上个小节中我们提到过,引入县城之后,县城成为了呃CPU调度的基本单位,但是如果这个县城是用用户级县城,这样的方式来实现的话,那么在这种情况下,其实CPU的调度单位依然是进程,操作系统是给进程分配CPU时间呢,因此即便我们电脑是多核处理机,但是由于进程,才是呃CPU调度的基本单位,因此这个进程只能被分配一个核心,所以这些线程并不能并行的运行,那这是早期的操作系统当中,人们实现现成的方式,在这个阶段操作系统还只支持进程,并不支持现成,那之后随着,
二、内核级线程
操作系统的发展,呃越来越多操作系统开始支持线程,那操作系统支持的一种线程,就叫做内合集的线程,那这种内合集现成,就是操作系统视角,也可以看得到的现成,那现代的操作系统大多都,支持内合集现成,比如说我们很熟悉的Windows Linux等等,那接下来我们,还是要思考同样的3个问题,在引入了内合集现成之后,这个现成的管理工作到底是谁来做呢,那由于这个内合集现成,是在操作系统层面实现的现成,因此这个内合集现成的管理工作,当然是需要由操作系统来完成,第二个问题,现成的切换是否需要CPU状态的转换,那既然这些内合集现成,由操作系统负责管理,那他们的切换,他们的管理工作,肯定是需要操作系统介入的,因此在进行现成切换的时候,当然是需要从用户态转变为内合态,第三个问题,操作系统,是否能够意识到内合集现场的存在,这个不用说了,最后我们根据刚才认知到的这些信息,来分析一下,这种实现方式有什么优点和缺点,首先来看优点,如果某一个操作系统,它支持内核及线程的话,那么在这种操作系统当中,内核及线程,它是处理机调度的基本单位,而进程只作为分配资源的基本单位,因此在多核CPU的环境下,这几个线程,可以分别分派到不同的核心下,呃并行的执行,另外呢不同的内合集线程中,可以跑不同的呃代码逻辑,比如说这个代码逻辑是实现视频聊天,这个是实现文字聊天,这个是实现文件传输,那么由于内合集线程,它是处理及分配的基本单位,那在这种情况下,即便其中的某一个线程啊被阻塞,那其他的两个线程,依然可以继续执行下去,所以采用这种方式有一个优点,那就是线程之间的并发能力强,那再来看一下这种方式的缺点,当引入了内合集现成之后,那一个进程有可能会对应,多个内合集现成,那操作系统需要对这些现成进行管理,所以内合集现成之间的切换,是需要CPU从用户台变为内合态的,当切换完成之后,还需要从内合态转转回用户态,而之前我们提到过很多次,CPU变态是有成本有开销的,所以这种实现方式,会导致现成的管理成本要更高,开销更大,那刚才我们学习了用户级,现成和内合集,现成这两种,现成的实现方式,那这两种方式都有各自的优点和缺点,那有没有可能,把这两种方式结合起来呢,
三、多线程模型
1、一对一模型
那在支持内合集现成的系统当中,如果在引入现成库的话,那么我们就可以实现,把若干个用户及现成,映射到某一个内合集现成这样的事情,那根据用户及现成和内合集,现成的这种映射,关系啊,就引出了3种多现成模型,像刚才我们一直在讲的这种模型,一个用户级现成对应一个内合级现成,这个是一对一模型,那如果采用这种映射方式的话,一个进程他有多少个用户级现成,就会有多少个内合级现成,他们都是一对应的,那这种方式的优点呢,就是刚才我们提到过的,一个县城被阻塞之后,别的县城还可以继续执行,因为内合集县城,是处理及分配的基本单位,另外这些代码逻辑,这些线程可以分派到多核处理机上,并行的执,行这是它的优点,而缺点呢,和刚才我们所说的一样,就是管理的成本高,开销大因为线程的管理工作,肯定需要切换到内核态,那只要涉及到CPU变态,就会使开销变大,那再来看第二种多线程,
2、多对一模型
模型叫做多对一,也就是多个用户级现成,映射到一个内合集现成,那如果是这种映射关系的话,其实它就退化成了我们之前提到的,纯粹的用户级现成那种实现方式,那由于一个进,程只被分配到了一个内合集的县城,而在这个内合集县城上面,通过县城库,又实现了3个用户级的县城,因此这些县城的管理工作,只需要在用户台下就可以完成,所以县城的管理开销小效率高,但是缺点呢,就是其中的一个用户及线程阻塞之后,会导致,其他的用户及线程也跟着被阻塞,并发性不高,并且这些用户及线程是不可能,并行的运行的,因为只有内合集,线程才是处理机的分配单位,如果一个进程,它只对应一个内合集线程的话,那么在同一时刻,这个进程,肯定只能被分配一个CPU的核心,当然如果给这个进程分配,多个内合集线程的话,那么在多核CPU环境下,这些内合集线,程肯定是可以并行的运行的,不过在我们的考试当中,如果提到这种多对一的线程模型的话,那么我们啊,默认一个进程,只被分配了一个内科技的线程,那最后我们要认识的是多对多,
3、多对多模型
多模型就是把,n个用户级线程映射到,m格内合集线程上,呃n的数量要大于等于m,那在这个模型当中,由于一个进程它有两个内合肌线程,因此其中一个内合肌线程被阻塞的话,另一个内合肌,线程是可以继续运行下去的,因此它克服了多对一模型,并发度不高的缺点,另方面,这种多对多的模型n是大于等于m的,也就是说内合集现成的数量,它要比用户集现成的数量要更小,因此,操作系统对这些现成的管理开销,也相应的会更小,而在一对一模型当中,有多少个用户级现成,就需要给他创建多少个,对应的内合集现成,那内合集现成太多的话,操作系统的管理开销就会更大,所以这种方式,他又克服了一对一模型当中,现成管理开销太大的一个缺点,那我们再来总结一下,用户级县城和内河级县城的,啊一个区别和联系,我们可以这么来理解,所谓用户级县城,我们可以把它理解为是,一个代码逻辑的载体,比如说这个用户级现成,它承载的是文字聊天相关的代码逻辑,这个用户级现成,它承载的是文件传输相关的代码逻辑,而内合级现成,可以理解为是运行机会的一个载体,因为操作系统在分配处理及,CPU资源的时候,是以内核及现成为单位进行分配的,所以在这边这个模型当中,虽然有3个用户及现成,但是啊这个进程最多只可,能被分配两个CPU的核心,我们的一段代码逻辑,只有获得了运行机会的时候,他才可以被CPU执行,那这可以让我们的县城管理,有更多的灵活性,比如说在这边这个例子当中,如果我们的QQ,视频聊天需要耗费比较多的CPU,资源的话,那么我们可以呃让,左边这个内合集线程,让它专门来,执行视频聊天相关的这个代码逻辑,而右边这个内合集线程,我们可以让它,并发的执行文件传输和,文字聊天这两个部分的逻辑,那如果某一个时刻,文件传输又要耗费很多的,CPU资源的话,那么我们可以把文字聊天这块的逻辑,把它映射到这边,让这个内合机线程来进行处理,那需要注意的是,在引入了内合集线程之后,一个进程可能会对应多个内合集线程,而只有所有的这些内合集线程,都被阻塞的时候,我们才说这个进程进入了阻塞状态,那根据去年同学们的反馈
四、总结
这个小节的内容也是不太容易理解的,特别是对于跨考的,没有自己写过程序的同学来说,呃可能理解起来比较吃力,对于跨考的同学来说,在学完了数据结构,有了一些这种呃写代码的思想之后,再回来理解这个部分的内容,可能也会更容易一些,我们需要再次强调的是,用户及现成是在用户视角能看到的,现成由现成库实现,就像那个很简单粗暴的y循环,可以认为是一个最,简单的现成库,那内合集现成,才是操作系统视角能看得到的,现成由操作系统来负责管理,所以,内合集现成才是处理及分配的单位,那,对于我们介绍这几种多现成模型来说,大家主要是要理解他们各自的优缺点,另外这个部分的内容比较容易呃考察,关于阻塞的问题,这个大家在课后习题当中会有体会,好的,那么以上就是这个小节的全部内容
No.7 线程的状态与转换
好现成的状态与转换,其实现成的状态与转换,和进程的状态与转换,呃几乎是一模一样的,并且现成的状态,我们通常只关注呃最核心
一、线程的状态和转换
呃最主要的这三个状态,也就是运行态就绪态和阻塞态,他们之间的转换,和进程之间的转换完全一致,如果一个系统他支持现程的话,那么一个运行态的现程,他被分配的时间用完了,那么他就会下处理机进入就绪态,而一个就绪态的线程,如果它被调度程序选中,那么就可以从就绪态回到运行态上,处理即运行,而一个正在运行的线程,如果它发出了呃某种请求,等待某个事件的发生,比如说等待IO完成,那么它就会从运行态转变为阻色态,而如果一个阻塞的线程,他等待的事件发生了,那么他就会从阻塞态回到就绪态,好所以这就是线程的状态与转换,我们着重关注这种三状态的模,型好接下来线
二、线程组织与控制
成的组织与控制,那其实现成的组织与控制,和进程的组织与控制也是非常类似的,在组织与控制进程的时候,操作系统会对进程的呃PCB,也就是进程控制快进行一个管理,其中包含了进程的各种各样的信息,那对于县城来说,要管理县城,我首先得给各个县城,建立一个与之对应的,呃一个数据结构,对吧那县城对应的数据结构就是TCB,也就是县城控制块,那每个县城控制块里边,会包含这样的一些内容,可以简称为TID,这和进程的PID是很类似的,其次每一个县城,他们执行的代码可能是各不相同的,因此每个县城,他执行到代码的哪个位置,是不是得把它记录下来,好,所以TCB当中还会包含呃程序计数器PC,用于指明线程现在执行到哪了,那如果一个线程它切换下处理机,那此时就需要把这个处理机上的PC,PC的值给它保存到TCB当中,而如果一个线程,它上处理机运行从旧绪态回到运行态,那这个线程的运行现场,运行环境是不是得被恢复,那就可以从这个TCB当中取出PC的值,把它放回PC计存器里面,这是属于现程运行现场的一个信息,那除了程序技术GPC之外,还需要保留其他的通用计存器,学过机组我们都知道,代码运行的中间结果,会被保存到各种各样的计存器里边,因此当我们切换现程的时候,是不是也需要保存这个现程的呃,各种计存器的一个值啊,那除了寄存器之外,还有一个重要的信息叫做堆站,那我们知道,堆站是用于保存函数调用的信息,a调用了b b调用了c,并且也会记录每一次的函数调用,它的返回地址是什么,a调用了b,那么b这个函数啊,调用结束之后,应该返回到a的哪一句代码,对吧,需要把这个函数的返回位置也给它,在堆站里边记录下来,同时啊每一层函数的局部变量,也会放在堆站里面,那现成的堆占啊,它可能是比较大的,是内存里的一大片区域,如果把这一整片区域都全部把它,放到TCB里,显然没必要,对吧,我们只需要保存堆占指针就可以,保存一个指针,那么我们可以通过这个指针,来找到这个线程,它的堆占在内存里的哪个位置,哪片区域就可以了,好所以还需要保存堆占指针,好所以这个地方,我把这三个部分把它圈起来了,程序计数器PC,以及其他各种计存器的值,还有堆占的信息,这些是现成,切换的时候我们需要保存和恢复的,一些现成的运行环境,下处理机的线程需要把这些信息,保存到TCB当中,而上处理机的线程,需要从TCB当中取出这些信息,然后把这些信息填回到相应的位置,那堆占指针通常是把它恢复到SP,堆占寄存器里面的啊,那除了上面这个信息之外TCB,当中还需要保存运行状态,运行态就绪态而阻色态,甚至如果是阻色态的话,呃还可以把阻色的原因什么的,就是更详细的给它进行一个记录好,最后还需要保存现成的优先级,那通常在现成调度或者,系统在分配资源的时候,可以根据现成的优先级,来进行一个呃分配,或者制定一个策略,好那这就是TCB当中,大致需要包含的一些内容,那有了TCB之后,每一个TCB这种数据结构,就可以表示一个现成,那我们把多个现成的TCB,给它组织起来,就可以形成一个现成表,组织的方式有很多种,比如说每个进程给他设置一张,呃现成表,或者系统当中所有的现成,组成一张现成表,当然也可以按照现成的状态不同,组织成不同的现成表,不同的系统可以采取不同的策略,总之所谓县城的组织,无非就是按照你的需求,把各个TCB啊,有规律的分门别类的把他们组织起来,分类管理,这就是县城的组织,那所谓县城的控制,就是要让县城在各种状态之间,来回切换,这就是县城的控制,所以这两个部分新增的内容,无非是把进城变成了县城而已,而县城往往比进城还要更简单,
No.8 调度的概念、层次
各位同学大家好,在这个小节中,我们会学习处理机调度的基本概念,和几个调度的层次,分别为高级调度中级调度和低级调度,其中由中级调度也就是内存调度,我们会引出补充一个,呃课本上没有太多提及的知识点,就是进程的挂起态,并且会介绍,一个进程状态的基状态模型,之后我们还会介绍,三个调度层次的联系和对比,那么首先来看
一、调度的概念
一下什么是调度,其实调度这个概念,和我们的生活离得并不遥远,比如说在我们去银行的时候,这个银行,他可能只有几个窗口可以为客户服务,那么这些客户到底应该先为谁服务呢,银行一般采用的就是先,到先服务的这种,这种原则,那如果说此时有一个VIP客户啊,这个客户在这个银行里存了几个,小目标就是存了几个亿,那么这个,VIP客户可能就会被银行优先的服务,他的优先级更高,再看另外一个场景,早上咱们起床的时候,可能每个宿舍只有一个卫生间,但是大家,都想成为这个坐在王座上的男人,那么每个人都想使用,但是有的人说我我想要使用3分钟,有的人要10分钟有的人要1分钟,还有一个人他也需要使用3分钟,那大家经过商量之后就决定了一种啊,使用这个,资源的一个原则,就是时间使用的短的可以让他先使用,而时间长的就后使用,如果说时间长度相同的,那么就先进入这个队列,先排队的就可以先使用,所以大家经过商量之后就决定用一,234这样的顺序来使用卫生间这个资源,所以其实所谓的调度他就是指当,我们有一堆东西,一堆任务要处理的时候,由于啊当前的资源有限,那么这些事情没办法同时的被处理,那这个时候我们就需要按照某种规则,比如说先到先服务,或者说时间短的优先,各种这样的规则来决定,我们要用什么样的顺序,来处理这些任务,这就是所谓的调度研究的问题,好的那来看一下在我们程序运行的
二、调度的三个层次
1、高级调度
整个生命周期内,什么时候会发生调度的情况,第一种调度叫做高级调度,又叫做作业调度,所以我们这需要补充作业的概念,那作业的概念其实在之前的讲解中,或多或少是提过的,那所谓的作业,其实指的就是某一个具体的任务,大家在书里面会看到这样的描述,就是说,用户向操作系统提交了一个作业,那这句话其实你可以理解为,就是用户让操作系统,帮他启动某一个特定的程序,然后这个程序,是来处理某一个具体的任务的,所以这就是作业的概念,好那我们知道我们要启动一个程序,那这个程序相关的数据,肯定需要从外存放到内存里边,但是我们的内存资源又是有限的,所以有时候如果内存已经满了,内存资源不足的话,那么我们给操作系统提交的这些作业,或者说我们想要,系统帮我们启动的这些个程序,有可能没办法马上把它们放到内存,马上启动,所以在这个时候,操作系统就会进行所谓的高级调度,或者也可以称之为作,业调度,操作系统会按照作业调度相关的规则,从这个所谓的作业后背对列里边,选择一个作业,先把它调入内存,并且会为这个作业,建立与它相对应的进程,也就是建立一个PCB,所以这就是所谓高级调度,或者说作业调度要做的事情,如果说当前用户提交了很多作业,那这个时候需要由操作系统来决定,到底要先调入哪个作业,那每个作业在整个生命周期内,只会掉入一次,掉入的时候会建立PCB,当作业完成或者说这个任务完成之后,作业会被调出,这个时候才会撤销与之对应的PCB,好那这是高级调度的概念,接下来看
2、低级调度
看低级调度,又可以叫进程调度或者叫处理机调度,因为我们内存里面其实同时会,存在很多很多个进程,但是我们系统当中的CPU,资源又是有限的,所以操作系统也需要制定某一种策略,从我们的,进程就绪队列当中挑选出一个进程,把处理机资源分配给他,那多道程序并发执行,这件事肯定需要用到进程调度,所以进程调度是操作系统当中最,基本的一种调度,并且进程调度的频率是很高的,因为只有高频率的进程调度,才可以让各个进程,呃很快速的轮流的上CPU执行,这样才可以让用户在宏观上看,好像各个进程是同时执行那样,好那只是低级调度,那最后再来看中级调度
3、中级调度
刚才我们说过,计算机当中,有可能会出现,这种内存资源不足的情况,内存里边同时会存在多个进程的数据,那如果说内存不足的话,其实我们可以让某一些不太紧急,不太重要的进程,先把这些进程的数据,把它从内存调出外存,那如果说一个进程的数据,从内存放到了外存里边,那这个进程此时就处于挂起状态,操作系统会把这些,处于挂起状态的进程,他们的PCB组织成一个队列,叫做挂起队列,其实就类似于我们之前学习过的,就绪队列,组色队列,那此时,如果说已经有空闲的内存资源了,那操作系统是不是又需要,通过某一种调度策略,来决定到底要先把哪个进程的数据,先把它调回内存,那这个就是所谓的终极调度管的事情,又叫做内存调度,不知道大家在平时用手机的时候,有没有这样的体验,就是呃有时候你切换程序,或者说切换进程的时候,有的时候你切换你会发现那个进程,切换的很快,而有的时候那个进程切换的又很慢,那有一种可能的原因就是,当你的这个进程切换的很快的时候,那这个进程的数据有可能是,放在内存里边的,而你发现切换进程很卡很慢的时候,有可能是因为你那个进程的数据,他之前已经不在你的手机内存里了,而是被系统调到了外存当中,所以当你切换这个进程的时候,哎,系统发现这个进程现在非运行不可了,那他会临时的,把这个进程相关的数据从,外存再读回内存,然后只有他读回内存之后,这个进程才可以顺利的运行,因此你会感受到有那么一丝丝的卡顿,其实卡顿的过程就是,系统在进行终极调度,他选中了你的那个进程,让他回内存来运行,那想要在进程运行的生命周期内,有可能会多次调出多次调入,所以中级调度发生的频率,肯定要比高级调度要更高,好的那这就是调度的3个层次,高级调度中级调度和低级调度,那么既然提到了挂期状态,我们再来补充一个和挂期状态,相关的期状态模型,
三、七状态模型
其实挂起状态,又可以进一步的细分为,就绪挂起和阻塞挂起两种状态,咱们之前已经学了进程的5状态模型,这也是408里,呃要求掌握的一个,一个进程的状态模型,但是对于一些自主命题的学校来说,有可能会考察7状态模型,所以大家也不要掉以轻心,那么在引入了旧绪挂,起和阻塞挂起两种状态之后,一个处于就绪态的进程,如果说此时这个系统的负载比较高,内存空间已经不够用了,那么,他有可能会把一个处于就绪态的进,程把它,放到把它暂时调到外存当中,然后这个进程,就进入了一个就绪挂起的状态,一直到内存空间空闲,或者说这个进程又需要继续执行,那这个进程又会被激活,把它的数据,相应的数据又挪回内存当中,这样的话,一个旧绪挂起的进程又回到了旧绪态,除此之外,一个处于阻色态的进程也可以被挂起,相应的啊也可以再重新的被调入内存,然后进行激活重新回到呃阻色态,而有的操作系统,有可能会使一个处于阻塞挂起的进程,当他等待的阻塞事件发生的时候,这个进程就会直接,进入到一个就绪挂起的状态,然后之后,当他再被重新被调回内存的时候,是直接回到就绪态而不是回到阻色态,而有的时候,一个进程当他处于运行,他运行结束之后,可能这个进程下处理机的时候,就会被直接放到外存当中,让他进入就绪化急的状态,而有的时候,一个处于创建态的进程,当他创建结束之后,创建完PCB之后,有可能出现内存空间不够的情况,那这种情况下,有可能处于创建态的进程之后,会先进入到一个就绪挂起的一个状态,那么这就是所谓的7状态模型,那大家需要注意的是,挂起和阻塞的区别,这两种状态是呃,都是,暂时不能获得CPU服务的两种状态,但是区别在于处于挂起态的进程,进程印象是放在外存里的,而处于阻塞态的进程,他的进程印象其实还在内存当中,而有的操作系统,有可能会把这些,处于就绪挂起和阻塞挂起的这些进程,分为两个不同的挂起对列啊,当然也有的操作系统,还会根据这个阻塞的原因不同,再把阻塞挂起的这些进程,再细分为多个对列,那么这就是漆状态模型,大家也需要注意一下,我们再来整理一下3层调度的联系和,
四、三种对比
对比这三层调度分别要做什么,相信刚才的讲解应该已经比较细了,这就不再展开,那么高级调度和中级调度,这两层调度,是发生在外存和内存之间的调度,区别在于高级调度,它是面向作业的调度,一个作业在刚开始会被调入一次,被调出一次,并且作业调入的时候,会会为这个作业建立相应的PCB,也就是建立它相应的进程,而中级调度内存调度,它是面向进程的一种调度,它是把暂时不会运行的进程,相关的进程印象相关的一些数据,把它调到外存里,然后之后通过中级调度,再,再把这些进程的数据从外存调回内存,而低级调度,它是内存和CPU之间的一个调度,对于这三层调度的发生频率来说,他们的发生频率依次是从低到高的,而这三种调度对进程状态的影响是,高级调度,他有可能会使一个进程从无到创建态,最后当他创建完了,PCB创建完毕之后,还会把这个进程放入到就绪队列里,让他进入就绪态,所以他对进程状态影响是这个样子,而内存调度,它会使一个处于挂起态的进程,重新回到就绪态,而如果说挂起态又细分为,阻色挂起和就绪挂起的话,那么也可以说,它可以使一个处于阻色挂起的进程,重新回到阻色态,而低级调度也就是进程调度,他是选择一个处于就绪态的进程,让他进入运行态,投入处理机开始运行,所以这是这三,种调度对进程状态的影响,那么我们再来简单,
五、总结
回顾一下这个小节,我们介绍了处理机调度的基本概念,和三个调度的层次,我们需要注意的是,这三种调度的后面一种名称,这三个名称才是在咱们的考题当中,最高频最容易出现的一种名称,所以这个大家需要注意,另外呢,我们需要理解三层调度的联系和对比,大家在脑子里再回忆一下对比一下,那么我们还呃,通过中级调度引出了一个咱们,书里没有,具体介绍的一个知识点,就是所谓的挂起态,并且介绍了和挂起态相关的,七状态模型,这两个知识点,其实在考试当中也是有可能被考到的,特别是自主命题的一些学校,那么最后我们需要注意的是,咱们在介绍这几种呃3层调度的时候,都是说他们都是按照某种规则,那么呃这个课当中,我们主要学习的是作业调度,和进程调度相关的这些所谓的规则,而这个就是咱们之后,要研究的调度算法的问题,好的那么这就是这个小节的全部内容,
No.9 进程调度的时机、切换与过程、方式
各位同学大家好,在这个小节中,我们会继续学习进程调度,相关的一系列知识点,首先我们会来回答下,进程调度的时机是什么,什么时候需要进行进程调度,而什么时候又不能进行进程调度,并且在聊这个进程调度实际的问题,的时候,会引出一个进程调度的方式的问题,分为非抢占式和抢占式两种,另外呢,进程调度的目的其实是为了进程切换,那么,进程切换和进程调度有什么区别呢,进程切换的过程当中,我们又需要做一些什么事情呢,这些都是这个小节的内容,好了那么我们,
一、进程调度的时机
先来看一下进程调度的时机,之前我们已经介绍了进程调度的概念,呃进程调度也叫做低级调度,就是指按照一定的算法,从就绪队列当中,选择一个进程为他分配处理机,那么,什么时候需要进行进程调度和切换呢,主要可以分为两个大类,第一种就是当前运行的这个进程,他主动的放弃了处理机,第二种是当前运行的进程,被动的被迫的放弃了处理机,比如说如果一个进程他正常的终止,或者因为运行的过程当中,发生了某种异常,而不得不终止,再或者一个进程他发出了一个IO请求,然后主动的请求进入阻塞状态,然后用来等待IO完成,这些情况,都是进程主动放弃,处理机的一个具体的例子,那被动放弃处理机就比如说呃,给一个进,给这个进程分配的时间片用完了,或者说有一个更紧急的事情需要处理,再或者当前有一个,优先级更高的进程进入了就绪队列,那么这些情况下又有可能需要呃,把这个当前运行的进程,强行的剥夺他的处理机使用权,然后他就不得不被动的放弃处理机,而进程调度,并不是什么时候都可以进行的,有的时候不能进行进程调度和切换,比如说在我们处理中断的过程当中,由于中断处理它的过程是很复杂的,并且和硬件是息息相关的,因此在中断处理的过程中是很难做到,呃就是中断处理处理到一半,去进行进程调度和切换的,而第二种情况是进程在,操作系统内和程序临界区中,这种情况也不能进行进程调度,这点不太容易理解,之后咱们还会继续展开细聊,第三种情况是在原子操作的过程中,也就是之前咱们介绍过的一些原语,比如说,咱们之前讲原语的时候举过一个例子,在一个进程他的状态发生改变,比如说从阻塞态变为就绪态的时候,那么我们继续要修改进程PCB当中,这个进程状态的标志位,同时也需要把PCB,放到一个新的相应的就绪队列里,那么如果说我们只做了前面这一件事,中间就开始进行进程切换进程调度了,那么就有可能会导致,PCB当中记录的这种状态标志,和PCB实际放的啊这个就绪队列,还是阻塞队列,实际放在这个位置,不相匹配的这种情况,而这种数据的不匹配,就有可能会为系统造成一些安全隐患,所以说,这种原语或者说原子操作中间的过程,肯定是不能允许进行进程切换的,那么接下来我们再来细聊一下,呃第二个问题进程,
在操作系统内和程序临界,区中不能进行调度与切换,这是正确的一种表述,但是,大家在做一个课后习题的时候会发现,12年的一个题当中有个选项是说,进程在处于临界区时不能进行,处理及调度,这个表述是错误的,在了解内核程序临界区,和普通的临界区的区别之前,我们需要先,聊一个现在暂时还没有接触的概念,叫做临界资源,临界资源就是指一个时间段内,只允许一个进程使用的资源,各个进程需要互斥的来访问临界资源,你访问的时候我不能访问,我访问的时候你不能访问,这是互斥的意思,那么临界区就是指,访问临界资源的那段代码,因此呃,各个进程肯定也只能,互斥的进入临界区,互斥的执行啊临这这一段,访问临界资源的代码,而内核程序的临界区也就是前者,一般就是用来访问,某一种内核数据结构的,比如说进程的就绪对列,那么当一个进程他,此时处于一个内核程序临界区,并且这个临界区,他是要访问就绪队列的话,那么在访问之前,他会把这个就绪队列上锁,而如果说这个进程,当前还没有推出内核程序临界区的话,也就意味着这个临界资源,并没有被解锁,那么在没有解锁的过程中,如果说我们要发生进程调度的话,那么进程调度相关的程序,肯定是需要访问就绪队列,这个临界资源的,因为他要从就绪队列当中,挑选一个进程,为他分配处理机,那么由于这个就绪队列,这个临界资源他此时还是上,锁的一个状态,所以如果说在这种情况下,去进行进程调度的话,那么这个进程调度肯定是没办法,顺利的进行下去的,因为此时这个还没有解锁,所以可以看到,对于内核程序临界区,访问的这些临界资源,也就是这些内核数据结构而言,如果这些内核数据结构啊,这些临界资源,被上锁了,并且没有被尽快的释放的话,那么有可能,会影响到操作系统内,和其他的管理工作,就比如说刚才咱们聊到的进程切换,所以说,我们在访问这些内核程序临界区的呃,时呃这些期间内,我们不能进行进程的调度和切换,我们必须让这个进程迅速的呃,尽快的执行完,内核程序临界区的那些代码,然后完成对这个临界资源的访问,之后就尽快的把这个,对临界资源的锁给解除,只有这样,其他的操作系统内核才可以继续呃,有序的进行管理工作,而另外一种情况,假如此时这个进程,访问的是一种普通的临界资源,比如说是一个打印机的话,那么他在访问他的时候,会开会先进行上锁,那打印机在完成打印完成之前,这个进程其实是一直在临界区内的,他还一直保持着对打印机的访问,但是由于他还没有推出临界区,所以这个临界资源并不会被解锁,但是打印机他又是一种慢速的IO设备,如果这个情况下,呃不允许进程调度进程切换的话,那么就会导致这个进程,他需要一直空,等着这个打印机的打印结束,所以在这个进程空等的过程当中,他同时还霸占着CPU,所以CPU可以说一直是在空闲的状态,他一直没有做一些有意义的事情,所以如果说呃,这个进程在访问一个普通的,临界资源,在一种普通的临界区当中的话,这个情况下,其实是应该进行进程调度的,因为普通的临界区,访问的这些普通的临界资源,并不会呃像之前所说的这个例子一样,直接的影响到操作系统,内核的管理工作,所以说为了增加系统的并发度,增加CPU的利用率,那么在访问这些普通的临界区的时候,是可以进行进程调度和切换的,那么讲到这里刚开始的这两个问题,为什么前者对为什么后者错,相信大家已经有所理解了,那么接下来我们再来看下
二、进程调度的方式
个问题在有的操作系统当中,他只允许进程主动的放弃处理机,而不允许这个进程在运行的过程中,被迫的被剥夺处理机资源,但是又有的操作系统他是允许啊,当有更紧急的人物处呃,需要处理的时候,他是会强行的,剥夺这个当前运行进程的,处理及资源的,所以由这个问题就是,当前运行的进程,是否可以被强行的剥夺处理及资源,这个问题我们引出了下一个知识点,就是进程调度的方式,分为非剥夺调度方式和剥夺调度方式,前者又可以称作非抢占式,后者又可以称作抢占式,那么,非剥夺调度方式就是咱们刚才聊到的,只允许啊,进程主动的放弃处理机这样一种方式,除非这个进程他正常或者异常的终止,或者他主动的要求进入阻塞他,不然这个处理机,是会一直为当前运行的这个进程,所呃为他服务的,那么抢占式或者说剥夺调度方式的话,如果说此时有一个更重要,更紧急的任务需要处理的话,那么,这个当前执行的进程就会被暂停执行,剥夺处理机资源,然后把处理机分配给更重要,更紧急的那个进程进行处理,那显然前面这种方式,它的这个规则会相对来说要简单一些,所以这种方式实现起来要简单,并且系统管理的开销也要更小,但是缺点就在于,他没有办法及时的处理紧急任务,所以呃这种非抢占式,只适合于早期的一些批处理系统,而后者抢占式,它可以优先的处理更紧急的进程,并且可以让各个进程按照,时间片轮转的这种方式来执行,当时间片到的时候,就可以强行的把当前运行的进程,把它的处理及资源给剥夺,所以说后面这种方式,它就比较适合于,后面,出现的分时操作系统和实时操作系统,这就是进程调度的方式的问题,分为这样两种,那么既然我们选,
三、进程的切换和过程
选择了一个进程,要为他分配处理机的话,在进程与进程切换的过程当中,又发生了一些什么事情呢,首先我们来聊一聊呃进程,狭义的,进程调度和进程切换有什么区别,狭义的进程调度指的是从就,绪队列中选中一个要运行的进程,这样一个过程,而这个要运行的进程,他可以是刚刚才暂停执行的进程,也可以是另一个进程,如果选中的是另一个进程的话,那么我们就需要进行进程切换,而进程切换指的就是,呃之前的那个进程让出处理机,然后之后的进程占用处理机,这样的一个过程,而有的题目当中出现的进程调度,它指的是广义的进程调度,广义的进程调度包含了进程切换和,选择一个进程,这样,这前面的就是前面所说的这两个步骤,所以在读题的时候,如果出现了两种调度的含义,大家不要觉得奇怪,自己能够分辨,它是狭义的还是广义的就可以了,进程切换的过程,主要完成了什么事情呢,其实我们可以把这个过程,简化为两件事情,一件事就是把,对原来正在运行的那个进程,他的各种数据,包括处理机的运行环境,这些数据把它保存下来,第二件事,就是把新的进程的各种各样的,运行环境之类的数据,把它恢复过来,而运行环境运行现场的一些信息,比如说程序计数器,程序状态自然各种数据寄存器,这些信息一般是存在,进程控制快PCB当中的,所以呃对这个数据进行保存,其实保存到了PCB当中,而对这些数据进行恢复,其实从PCB当中读出这些数据,并且把这些数据,放到相应的寄存器当中,那么经过刚才的分析我们会发现,进程的切换,其实其实并不是啊一瞬间就可以,完成的,它是需要付出一定的时间代价的,所以我们不能简单的认为,进程切换越频繁,进程的并发度就越高,如果进程的切换调度过于频繁的话,其实反而会导致整个系统的效率,降低因为系统会把大部分的时间,都花在这个进程,切换的这个开销上,而真正用于执行进程,推进进程的时间反而会减少,所以进程切换是有代价的,了解这一点,对于理解咱们之后讲时间片的,一个调度算法呃,是至关重要的,这个地方大家稍微注意一下,好的那么我们再来快速
四、总结
就回顾一下这个小节的内容,这个小节的内容并不多,并且也不算是考试的重点,不过大家也需要理解,首先我们介绍了进程调度的时机,包括什么时候需要进程调度啊,分为进程主动放气处理机和进程,被动放气处理机,这两种情况,并且我们举了一系列的例子,之后我们介绍什么时候,不能进行进程调度,重点介绍了,进程在操作系统内核程序临界区当中,为什么不能进行进程啊调度,因为呃这个时候进程进行进程调度,有可能会影响到,操作系统内核的一系列管理工作,而如果进程处于一个普通的程,序临界区当中,他访问的是一个普通的临界资源的话,这种情况下是可以进行,进行进程调度的,这点是不太容易理解的难点,但是也不算重点,那么之后我们要介绍进程切换的过程,其中大家最需要,注意最需要理解的是,进程的调度和切换是有代价的,只需要知道这一点就可以了,其他的这些,要有一个大体的印象就可以,另外呢,我们还介绍了进程调度的两种方式,分为强战士和非强战士,而这两种调度方式,会在之后咱们讲调度算法的时候,大量的出现,所以继续学习后面的内容,会对这两个部分的理解会更加深入,好的那么这就是这个小节的全部内容
No.10 调度器和闲逛进程
接下来调度器或者叫调度程序,很简单的一个概念,调度程序是操作系,同内核的一个呃,非常非常重要的呃一个程序模块,我们说一个进程,会在就绪运行阻塞之间来回横跳,那2和3这两个呃状态的转换,就是由调度程序来负责完成的,操作系统的调度程序,要决定这样的两个事,首先让谁去运行,这就涉及到这个调度程序,它采用的调度算法是什么,先来先服务,短作业优先还是时间片轮转等等,那除了让谁运行之外,还需要决定运行多长时间,不同的进程,可以给他分配不同的时间片大小,好所以这就是操作系统的调度程序,反正就是用来管调度的,当前运行的进程要不要让他下处理机,如果他下了处理机,那么接下来就去对列里的这些进程,要让谁上处理机运行,这就调查程序要管的一个事情,那之前我们讲过这样的一个知识点,叫做进程的调,度时机,那现在我们也可以换一种说法,就是,什么样的事件会触发这个调度程序啊,他开始工作,首先创建一个新进程的时候,这旧区队列是不是会发生改变,那旧区队列一变,是不是就有可能让这个呃新进程抢占,当前正在运行的这个进程的一个CPU,所以创建新进程的时候,调度程序哎会出来工作一下,检查一下要不要让这家伙上处理机啊,除此之外,进程退出也会触发调度程序的工作,一个正在运行的进程,他此时决定自己终结自己对吧,那他终结了自己处理机不就空闲了吗,因此调度程序就得出来看一下,接下来让谁上处理机工作好,除此之外,一个正在运行的进程阻塞,显然也需要调度程序出来看一下对吧,接下来让谁上处理机,再者发生i o中断的时候,有可能使得某些阻塞进程回到角序态,那同样的原理,只要就绪队列一改变,那么调度程序就需要啊出来检查一下,这新旧绪的进程,应不应该让他上处理机运行,应不应该让他抢占等等好,另一点值得注意的是,如果我们采用的是非,抢占式的调度策略,那么只有运行的进程,阻塞或者退出的时候,才会触发这个调度程序的工作,而如果采用的是抢占式的策略,那么每个时钟中段,或者每k个时钟中段,都会触发调度程序出来呃检查工作,这个很好理解吧,如果是抢占式的调度策略,那就意味着只要旧绪队列一改变,那就必须,检查一下新旧绪的进程,有没有可能抢占,当前正在运行的这些进程,那这个检查的动作,就是由时钟中断来触发的,每过一个时钟周期,或者每过k个时钟周期,都例行的唤醒一下这个调度程序,让他来检查,此时就绪队列有没有新进程到达,如果有那么,需不需要让他抢占,当前正在运行的进程,而如果是非抢占式的调度策略,那只有当前运行的进程,他主动放弃处理机的时候,才有必要唤醒这个调度程序,让他检查一下,对吧平时只要这个进程还在运行,那我们就没有必要频繁的唤醒,这个调度程序,因此非抢占式的这个调度策略,不会由时钟中断来唤醒调度程序,而这就是所谓的调度程序,你只需要知道他是干嘛的,以及什么时候,这家伙会出来工作就可以了,那刚才我们说调度的时候,我们说的是进程的调度,如果一个系统他支持的不只是进程,还支持现程,那么调度程,
No.11 调度算法的评价指标
各位同学大家好,在这个小节中,我们会学习,一系列用于评,价一个调度算法好坏的一些评价指标,包括CPU利用率系统吞吐量,周转时间等待时间和响应时间,那在学习的过程中,大家要,注意理解各个指标为什么这么设计,并且要会计算每一个指标,首先来看
一、CPU利用率
下什么是CPU利用率,其实在早,期的呃计算机当中,计算机的造价是很昂贵的,特别是CPU,这个部件的造价占了很大一部分,它这这个东西,基本上就是用钱堆出来的,一个一个很奢侈的东西,并且在现代的这些计算机当中,其实CPU也不便宜,所以因为CPU这么贵,那么人们就会希望让CPU,尽可能多的为人们工作,所以就设计了一个叫做CPU,利用率的这样一个指标,这个指标就是用来呃,就是用来表示CPU处于忙碌的时间,占总时间的比例,那么这个利用率就可以啊,用忙碌的时间比上总时间,就可以算出这个利用率啊,但是有的题目,它不仅仅是会让我们算CPU利用率,还会让我们算某种,比如说某种IO设备的利用率,比如说如果呃一个计算机当中,他只支持单道程序,然后有个作业,刚开始的时候需要在CPU运行5秒,然后打印输出5秒之后再执行5秒,然后就结束,那么在这个过程中CPU利用率就是呃,就是先刚开始运行了5秒,然后之后又运行了5秒,总共运行了10秒,CPU处于忙碌的时间是10秒,然后整个过程处理的时间是5+5+5也就15,那么就是66.66%将近是这样子,然后打印机的利用率的话,就是打印机处于忙碌的时间,也就是5秒,在比上总时间那么就是33.33%,大概是这样,但是在真正的考研题目当中,通常会考察多道程序并发执行的情况,这种情况下,大家可以用班特图来辅助计算这,个地方先不展开,在课后习题会有遇到,并且也会有相应的讲解,那么第二个评,
二、系统吞吐量
评价的指标就是叫做系统吞吐量,那么对于计算机来说,呃计算机他肯定是希望,用尽可能少的时间,可以处理完尽可能多的作业,所以就呃,设计了一个叫做系统吞吐量的指标,用来表示,单位时间内完成了多少道作业,所以系统吞吐量可以用,总共完成了多少道作业,再除以总共花了多少时间,就可以算得系统吞吐量,比如说有个计算机,处理完10道作业花了100秒,那么吞吐量就是10/100,那么就是0.1道每秒,也就是平均每秒可以完成0.1道作业,这就是单位时间内完成的作业的数量,那这就是系统吞吐量,第三个指标是周转时
三、周转时间
对于计算机的用户来说,这个用户肯定是很关心,自己的作业从提交到完成,总共花了多少时间,一般来说,这个时间当然是花的越少越好,所以周转时间就是用来反映这样一个,呃所花费时间的一个指标,就是指从作业被提交给系统开始,到作业完成为止,这段时间到底有多长,那么它总共包作业,这个周转时间总共包括4个部分,就是作业在后外存的后备堆列上,等待被作业调度的时间,然后进程在就绪堆列上的时间,还有进程处于运行态的时间,还有进程处于阻塞态的时间,后面的这3项就是就绪态运行态,和进程和阻塞态,这三项,在整个作业的这处理过程当中,是会发生多次的,整个过程中只会有一次作业调度,这个咱们在之前的小节当中,也有介绍过,所以周转一个作业的周转时间,我们可以用作业的完成时间,减掉作业被提交给系统的时间,这样就可以简单的计算出来啊,另外呢对于操作系统来说,他肯定是会更关心整体,系统的整体表现,所以他会更关心所有的作业,周转时间的一个平均值,所以,就有另外一个指标叫做平均周转时间,就是用各个作业的周转时间之和,再除以再再除以作业的数量,那么我们再来呃思考一个这样的问题,对于各个用户提交的这些作业来说,有的作业它的运行时间是短的,有的作业运行时间是长的,所以说如果在周转时间相同的情况下,其实运行时间,啊更长的那些那些那些作业,对于用户来说,肯定感受会稍微更好一些,举一个很直观的一个有味道的例子,比如说我们去排队等厕所,那么你本来只需要呃使用1分钟,但是你要排队排10分钟,就是总共整个周转过程,你总共花了11分钟,这种这种感受肯定是很糟糕的,本来自己只需要用一会,但是又需要等待那么长的时间,不过对于另外一个人来说,他总共需要使用十分钟,但是他只需要等一分钟,所以另外这个人,他的整个周转时间其实也是11分钟,只不过呃,这11分钟当中,只有一分钟是用来等待的,所以对于第二个人来说,这一分钟的等待其实对他来说,感受没有那么糟糕,所以这就是,呃在周转时间相同的情况下,啊作业的这个实际运行时间长短不同,所导致的对于用户的感受的这种区别,因此,人们又提出了另外一个指标叫做待权,啊啊周转时间,就是指作业的周转时间,在比上作业实际运行的时间,因此可以看到,对于周转时间相同的两个作业来说,他的如果哪个作业的实际运行时间,更长那么这个作业啊,相应的被服务的这个时间,所占的比例也就更多,那么这个待全的周转时间就会更小,用户满意度相应的也会更高,而对于实际运行时间,相同的两个作业来说,肯定是周转时间短的那个作业,对于用户来说他的满意度会更高,那么周转时间短的话相应的待全,周转时间也会更小,所以通过这个式子我们会发现,待全周转时间他肯定是大于等于一的,因为呃,周转时间包含了作业的实际运行时间,他肯定比实际运行时间要更大,那么待全周转时间和周转时间都,呃都是一样的,他们肯定都是呃越小越越小,对于用户的体验来说就会越好,相应的和平均周转时间一样,也会有一个所谓的平均待全周转时间,这个就是系统会比较关心的一个指标,呃,这个就是把各个作业的待全周转时间,给加合起来,最后再除以一个作业数,那么这就是周转时间相关的4个指标,接下来我们再来看下一个
四、等待时间
指标叫等待时间,对于计算机的用户来说,肯定是希望自己的作业啊,尽可能少的等待处理机,那么等待时间就是用来,度量这个用户的作业,等待处理机啊,被等待被服务的这个时间之和,到底是多少,等待越长肯定用户的啊满意度就越低,那么我们先来看一下,当一个作业刚开始被提交的时候,它是被放到了外存中的,作业后备对列当中,作业在后备队列当中需要等待被服务,也就是被作业调度,当他被调度以后,这个作业就会呃放到内存当中,并且建立起相应的进程,当这个进程建立了之后,他会被CPU服务也会被IO设备服务,当然也会有,等待被服务的这样一些时间,一直到最后整个进程结束,然后把作业移出内存,那么对于进程来说,一个进程的等待时间,其实指的就是这个进程被建立起之后,开始呃开,开始累计,他等待被服务的时间总和是多少,但是需要注意的是,他在等待IO完成的这个期间,其实是正在啊被正在被IO设备服务的,所以,这种时间是不能算到等待时间里的,另外呢对于作业来说,我们不仅要考虑他呃,建立了相应的进程,之后的这一系列的等待时间,我们还要加上,他在外存的后备队列当中,等待被调度的这一段时间,所以呃,作业的等待时间和进程的等待时间,计算起来是有一些不同的,这个稍微注意一下,通过之后的课后习,题大家会发现一个现象,就是一般来说一个作业,他总共需要被CPU服务多久,被IO设备服务多久,这些,这个总时间一般来说都是确定不变的,所以调度算法其实只会影响作业,或者说进程的,等待时间,当然和之前的那些指标一样,等待时间也有一个对应的,与他对应的指标,叫做平均等待时间,那么平均等待时间,就是把所有进程或者作业的等待时间,做一个加和,再除以作业的数量就可以了,最后我们再来讲一个
五、响应时间
呃叫做响应时间的一个指标,对计算机用户来说,如果说他提交了一个请求,比如说,就是在键盘里输入了一个调试命令,那么他肯定是希望尽早的被,呃系统服务,被回应他提出的这个请求,所以响应时间,指的就是这个用户从提出请求,到首次产生响应所用的时间,这就是响应时间,好的那么我们再来回顾一下这个小节,我们介绍了5种
六、总结
用来评价调度算法的指标,那么大家要理解,各个指标为什么这么设计,并且还会还要会计算各个指标,其中CPU利用率和系统吞吐量,咱们举了一两个比较简单的例子,后面的其他的这些指标,我们会在之后的,对于算法的讲解当中在,不断的进行实践,所以这个地方暂时没给出具体的例子,那这个小节当中比较容易忘记的是,待全周转时间和平均待全周,转时间这两个指标,那么大家需要结合,咱们举的那个比较有味道的例子,来理解这个指标为什么这么设计,只要理解了其实记住它就不难了,好的那么这就是这个小节的全部内容,,
,另外呢对于作业来说,我们不仅要考虑他呃,建立了相应的进程,之后的这一系列的等待时间,我们还要加上,他在外存的后备队列当中,等待被调度的这一段时间,所以呃,作业的等待时间和进程的等待时间,计算起来是有一些不同的,这个稍微注意一下,通过之后的课后习,题大家会发现一个现象,就是一般来说一个作业,他总共需要被CPU服务多久,被IO设备服务多久,这些,这个总时间一般来说都是确定不变的,所以调度算法其实只会影响作业,或者说进程的,等待时间,当然和之前的那些指标一样,等待时间也有一个对应的,与他对应的指标,叫做平均等待时间,那么平均等待时间,就是把所有进程或者作业的等待时间,做一个加和,再除以作业的数量就可以了,最后我们再来讲一个
[外链图片转存中…(img-8wyL12vA-1692438038912)]
五、响应时间
呃叫做响应时间的一个指标,对计算机用户来说,如果说他提交了一个请求,比如说,就是在键盘里输入了一个调试命令,那么他肯定是希望尽早的被,呃系统服务,被回应他提出的这个请求,所以响应时间,指的就是这个用户从提出请求,到首次产生响应所用的时间,这就是响应时间,好的那么我们再来回顾一下这个小节,我们介绍了5种
[外链图片转存中…(img-3fBHJw8r-1692438038913)]
六、总结
用来评价调度算法的指标,那么大家要理解,各个指标为什么这么设计,并且还会还要会计算各个指标,其中CPU利用率和系统吞吐量,咱们举了一两个比较简单的例子,后面的其他的这些指标,我们会在之后的,对于算法的讲解当中在,不断的进行实践,所以这个地方暂时没给出具体的例子,那这个小节当中比较容易忘记的是,待全周转时间和平均待全周,转时间这两个指标,那么大家需要结合,咱们举的那个比较有味道的例子,来理解这个指标为什么这么设计,只要理解了其实记住它就不难了,好的那么这就是这个小节的全部内容,,
[外链图片转存中…(img-7ixAfTWY-1692438038913)]