操作系统 | 2.1 多进程图像
哈工大,李治军老师,操作系统公开课
1. CPU管理的直观想法
要想管理CPU,首先要知道怎么使用CPU
(1) CPU的工作原理
| 核心:取值执行 |
- CPU是怎样工作的?

- CPU工作的核心,就是取值执行。即PC指针从内存里取出一条指令然后执行,再把取值指针自动加一,再取值执行,如此循环往复。
- CPU怎么开始工作?

- 由于PC指针是自动累加的,因此,只需要设置好PC的初值就可以了。
(2) 只设置PC初值,然后让计算机自己执行,会有问题吗?
| 看看下面代码有什么问题,要怎么解决? |

fprintf是I/O指令,由于要操作磁臂(机械),所以执行速度较慢,在执行I/O指令时,CPU等待不做任何工作;i++;是计算指令,直接在电路上工作,在CPU直接计算。- 结论:根据图片可以发现 —— 执行一条I/O指令的时间,几乎可以执行100万条计算指令。
| 假如代码中,平均每20条计算指令,有一条I/O指令。那么,CPU的利用率几乎为0。但是CPU资源极其珍贵,怎么提高利用率呢? |
<1> 提过CPU利用率
- 主要思想:当一个程序进入I/O指令时,CPU就跳到另一个程序执行。
- 多道程序、交替执行
<2> 一个CPU上交替的执行多个程序:并发

| 问题:切出去好办,把PC指针指向另外一个程序即可。但是,切回来时,怎么办????? |
-
在上面例子中,思考上面提出的问题:
- 程序一执行到52,此时,ax=1+1=2, bx=1
- 跳转到程序二,执行到202;此时, ax=10+10=20, bx=10。
- 再跳转到程序一,执行53。
- 问题来了:ax和bx的值都已经改变了,怎么办呢???
-
每一个程序都有一个存放信息的结构PCB

- PCB存放了当前程序的信息,CPU切回来之后,通过PCB修改寄存器的状态。
<3> 引入进程
- 我们已经说到,静态的程序和运行中的程序是不一样的。
- 静态的程序不需要记录状态,不需要PCB;
- 执行的程序必须记录状态,需要PCB。
- 那么,我们就需要一个东西来区分静态的程序和运行中的程序。
-
进程:进行(执行)中的程序 -
进程有开始,有结束;而程序没有
-
进程会走走停停,走停堆程序无意义
-
进程需要记录ax, bx, ...,程序不用
-
...
-
2. 多进程图像
| 为了让CPU高效的工作,需要让CPU跑多个进程,交替执行。这就是多进程图像 |
(1) 多进程图像引入
<1> 多进程图像引入

- 系统中有三个进程,PID就是进程号
- 每一个进程都有一个PCB。(PCB:Process Control Block 进程控制块)
<2> 多进程图像从启动开始到关机结束

(2) 多进程如何组织

| 多进程的组织:PCB+状态+队列 |
<1> 状态转移图

- 这里不再详细展开
<2> 多进程如何交替
| 交替的三部分:队列操作+调度+切换 |
- 当程序A执行遇到I/O操作时,在当前的PCB中,将其状态转换为阻塞态,然后将其放在阻塞队列中;
- 执行schedule()函数(后面详细学习)
- 简单说,在schedule()函数内:
- 从就绪队列中取出一个进程。(取哪个进程,就是调度算法)
- 将执行的当前进程切换为为新取出来的进程。
- 简单说调度
- FIFO(先进先出,按序排队)
- FIFO显然是公平的策略
- FIFO显然没有考虑进程执行的任务的区别
- Priority(优先级)
- 优先级应该怎么定?可能使某些进程饥饿
- FIFO(先进先出,按序排队)
- 简单说切换

- 先将当前CPU中寄存器的状态保存到当前进程的PCB中;
- 再将要切换进程的PCB中的寄存器状态赋值到CPU寄存器中。
- 必须使用汇编。
<3> 多进程之间如何影响
| 多个进程都处于用户态,在程序使用内存怎么保证不会冲突? |
-
怎么避免以下问题?

- 进程1中的代码,要把10100b赋值给ax,然后由ax赋值到内存地址为100的地方;
- 但是,内存地址100的地方,是进程2的代码。假如成功赋值的话,程序2会崩溃。
-
解决办法:地址空间分离

- 在这里,100只是逻辑地址,并不是真正的物理地址;
- 虽然在两个进程中,都对地址100进行访问,但是通过映射表,对应的真实物理内存并不是同一个地方。
| 假如说真的要访问同一块地址(物理地址),进程之间怎么合作呢? |
<4> 多进程之间如何合作
- 生产者消费者
-
生产者消费者实例:

- 生产者进程:往共享内存中写入数据。(如果满了,死循环;不满的话,可以写入数据,写完counter加1)
- 消费者进程:从共享内容中取出数据。(如果为空,死循环;不空的话,可以取;取完counter减1)
-
两个进程都要修改counter
-
一种可能的情况

- 在这个可能的执行序列中,存在有下面问题:
- 步骤1(此时是生产者进程):将counter=5赋值给P.register
- 步骤2(此时是生产者进程):将P.register+1=6赋值给P.register
- 进程切换
- 步骤3(此时是消费者进程):将counter=5赋值给C.register
- 步骤4(此时是消费者进程):将C.register-1=4赋值给C.register
- 进程切换
- 步骤5(此时是生产者进程):将P.register=6赋值给counter
- 步骤6(此时是消费者进程):将C.register=4赋值给counter
- 最终结果:counter=4。造成错误!!!
-
- 进程同步:(例子:给生产者消费者 加锁)
- 加锁之后的流程图

- 步骤1(此时是生产者进程):检查到没有锁;然后给counter上锁
- 步骤2(此时是生产者进程):将counter=5赋值给P.register
- 步骤3(此时是生产者进程):将P.register+1=6赋值给P.register
- 步骤4(此时是消费者进程):检查counter锁,有锁,不执行消费者进程
- 步骤5(此时是生产者进程):将P.register=6赋值给counter
- 步骤6(此时是生产者进程):给counter开锁
- 步骤7(此时是消费者进程):检查到没有锁;给counter上锁
- 步骤8(此时是消费者进程):将counter=6赋值给C.register
- 步骤9(此时是消费者进程):将C.register-1=5赋值给C.register
- 步骤10(此时是消费者进程):将C.register=5赋值给counter
- 步骤11(此时是消费者进程):给counter开锁
- 加锁之后的流程图
3. 本文总结
1. CPU管理的直观想法
CPU工作原理:取值执行;
逻辑路线:
(1) CPU执行“I/O”操作是执行“计算操作”耗时的100万倍,因此,当计算机执行“I/O操作”时,CPU空闲造成资源浪费。
(2) 为了解决这个问题,让CPU交替执行不同的程序吗,提高CPU使用率。
(3) 为了更提高CPU使用率,不等“I/O操作时”才切换程序,使程序并发执行。
(4) 至此,引入了进程的概念。
(5) 在切换时,要保存当前进程的状态,并恢复被切换进程的状态。这就是是PCB的作用。
2. 多进程图像
计算机的核心图像
(1) 多进程的组织:PCB + 状态 + 队列
(2) 引入了状态的概念,以及理解状态转移图
(3) 多进程之间如何交替:队列操作+调度+切换
<1> 调度 FIFO、Priority
<2> 切换 switch_to(pCur,pNew)
(4) 多进程在使用时,程序A要操作的地址,会对程序B产生影响,怎么办?
<1> 使用映射表。这就使得地址空间分离
<2> 程序A操作的地址,并不是真正的地址。只是一个逻辑地址,通过映射表才能找到真正的物理地址。
(5) 进程合作(两个进程要访问一个共享空间,并更改一个值,怎么办)
<1> 生产者、消费者模型
<2> 由于CPU并发执行,两个进程更改一个地址的值时,执行序列会对结果产生影响。
<3> 要解决这个问题,就需要 加锁!!!


浙公网安备 33010602011771号