谈谈操作系统的多进程

操作系统的多进程图像

操作系统主要控制计算机的硬件,而其中最重要的就是CPU,因此操作系统的最主要工作就是控制CPU更好地执行命令,那么在介绍进程之前,我们首先来了解一下CPU的工作原理是怎样的。

一、CPU的工作模式

首先,CPU取出程序指针PC,然后到对应的寄存器中取出地址为PC的指令,通过译码来分析指令的内容,移动相应寄存器的内容来实现指令,最后程序指针PC指向下一条指令,CPU重复上述工作过程。总的来说,CPU的工作模式就是 “取址-译码-执行”。比如CPU执行如下所示的指令:

50: mov ax, [100]
51: mov bx, [101]
52: add ax, bx
......
100: 1
101: 2

首先,PC 指针被设置为 50,CPU取出指令 mov ax, [100] 执行,将内存地址为 100 中的数据移动到寄存器 ax 中。当 50 中的指令完成后,PC指针指向 51,CPU执行 mov bx, [101],最后 PC 指向 52,将 ax 和 bx 的数据相加,此时 ax=3

这种工作模式在只能等待某一段程序执行完成之后才能执行另外一段,那么当正在执行的程序卡在某一条指令时(比如读取磁盘上的数据,调用IO等),CPU就会停在这里等待该指令完成,因此CPU的利用率很低。

二、多道程序系统

多道程序系统是在计算机内存中同时存放几道相互独立的程序,使它们在管理程序控制之下,相互穿插的运行 (系统由一个程序转而运行另一个程序时需要使用中断机构中断正在运行的程序) ,以使系统中的各种资源尽可能地满负荷工作,从而提高整个计算机系统的使用效率。 两个或两个以上程序在计算机系统中同处于开始和结束之间的状态,这就称为多道程序系统。其技术运行的特征:多道、宏观上并行、微观上串行。如下图所示:

如上图所示:

  1. 单道程序的 CPU 和 DEV 的执行效率为:CPU=(10+5+10+10+5)/80=0.5,DEV=(5+10+10+5+10)/80=0.5CPU=(10+5+10+10+5)/80=0.5,DEV=(5+10+10+5+10)/80=0.5
  2. 多道程序的 CPU 和 DEV 的执行效率为:CPU=(10+10+5+5+10)/45=0.89,DEV=(10+5+5+10+10)/45=0.89CPU=(10+10+5+5+10)/45=0.89,DEV=(10+5+5+10+10)/45=0.89

因此,多道程序系统能够显著提高 CPU 和 DEV 的利用率。在程序运行的时候,每个程序都需要 PC 以及各种寄存器来描述程序的运行状态,那么这些运行着的程序就叫做进程。通过上述分析,我们可以将进程的特征总结如下:

  1. 动态性:进程是程序的一次执行,它有着创建、活动、暂停、终止等过程,具有一定的生命周期,是动态地产生、变化和消亡的。动态性是进程最基本的特征。
  2. 并发性:指多个进程实体同时存于内存中,能在一段时间内同时运行。并发性是进程的重要特征,同时也是操作系统的重要特征。引入进程的目的就是为了使程序能与其他进程的程序并发执行,以提高资源利用率。
  3. 独立性:指进程实体是一个能独立运行、独立获得资源和独立接受调度的基本单元。凡未建立PCB的程序都不能作为一个独立的单元参与运行。
  4. 异步性:由于进程的相互制约,使得进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进。异步性会导致执行结果的不可再现性,为此在操作系统中必须配置相应的进程同步机制。
  5. 结构性:每个进程都配置一个PCB对其进行描述。从结构上看,进程实体是由程序段、数据段和进程控制块三部分组成的。

三、多进程图像

3.1进程的状态转换

根据进程的运行状态,可以把进程简单地分为新建态,就绪态,运行态,阻塞态和终止态五种状态。比如,你去食堂打饭,那么排队的人组成了一个队列,1)每个处在队列的人的状态就是就绪态;2)同一时刻窗口只能处理一个人的请求,因此正在处理的那个人被称为运行态;3)但是当准备打饭的时候忘了带饭卡,这个人就从运行态变为阻塞态,直到取回饭卡又变成就绪态。进程之间的状态转换如下图所示:

3.2 进程的切换

在同一时刻,内存中存在多个进程,可以根据用户的操作而进行切换。那么进程切换的具体过程是怎样的呢?如下图所示,假设内存中有两个进程,在进程1执行过程中切换到进程2 ,此时:1)记录下进程1中的PC指针,否则无法切换回来; 2)将PC指针切换为进程2的程序开始为止,开始执行进程2。

但是,由于在执行进程2的过程中,更改了寄存器 ax, bx 的值,因此再次切回到进程1时,52号命令 'add ax, bx' 执行完毕后 ax 中的值为 50,而非 1。因此在进程切换时,除了要记录下程序指针 PC 之外,还要记录一些与进程1 密切相关的寄存器的值,这个存放信息的结构被称为进程控制块(Progress Control Block, PCB)。当再次切换回来时,首先加载进程1 的PCB中的数据,然后执行相应的指令。因此,根据上述分析,进程之间的切换可以描述为:

switch_to(pCur, pNew) //pCur 表示当前进程的PCB,pNew 表示待切换进程的PCB
{
	// 将当前执行进程的状态保存在PCB中
	pCur.ax = CPU.ax;
	pCur.bx = CPU.bx;
	...
	pCur.cs = CPU.cs;
	pCur.pc = CPU.pc;
	// 加载新的进程的PCB,执行新的进程
	CPU.ax = pNew.ax;
	CPU.bx = pNew.bx;
	...
	CPU.cs = pNew.cs;
	CPU.pc = pNew.pc;
}

3.3 进程的调度策略

由于在就绪队列中存在多个就绪态的进程,那么在进行进程调度时也必须遵守一定的原则,最常见的是:

  1. 高级调度: 又称作业调度、长程调度。从输入系统的一批作业(job, 用户提交给操作系统计算的一个独立任务)中按照预定的调度策略挑选若干作业进入内存,为其分配所需资源并创建对应作业的用户进程。
  2. 中级调度: 又称平衡调度,中程调度。根据内存资源情况决定内存所能容纳的进程数目,并完成外存和内存中进程对换工作。
  3. 低级调度:又称进程调度/线程调度,短程调度。根据某种原则决定就绪队列中那个进程/线程先获得处理器,并将处理器出让给它使用。

其中常见的低级调度算法主要包括:

  1. 先来先服务(First Come First Server, FCFS)算法。
  2. 最短作业优先(Shortest Job First, SJF)算法。
  3. 最短剩余时间优先(Shortest Remaining Time First, SRTF)算法: 假设当前某进程/线程正在运行,如果有新进程/线程移入就绪队列,若它所需的CPU运行时间比当前运行的进程/线程所需的剩余CPU时间还短,抢占式最短作业优先算法强行剥夺当前执行者的控制权,调度新进程/线程执行。
  4. 最高响应比优先(Highest Response Ratio First, HRRF)算法:非剥夺式算法。其中,响应比 = (作业已等待时间 + 作业处理时间) / 作业处理时间。
  5. 优先级调度算法:优先级高的选择进程/线程优先选择。
  6. 轮转调度(Round-Robin, RR)算法: 也称时间片调度。就绪队列的进程轮流运行一个时间片。
  7. 多级反馈队列(Multi-Level Feedback Queue, MLFQ)算法。

3.4 多进程之间相互影响

想象一下,如果进程1的程序中有 mov [100], ax 而恰好在这个时刻CPU需要切换到进程2,进程2的开始指令刚好存在100的内存地址中。由于进程1中干扰了内存100中的数据,造成进程2损坏。为了使多个进程能够在内存中很好地共存,操作系统给每个进程单独分配一段内存空间,通过映射表将进程中的内存映射为该内存空间的一块区域。如此,虽然在代码中所使用的逻辑地址是一样的,但是通过映射表所得到的实际物理地址是不同的。如下图所示:

3.5 进程之间的通信

有的时候,多个进程之间需要进行合作,共享同一块缓冲区,比如打印(PPT,PDF,Word都可以打印),首先每个进程需要往打印队列中存入数据,由于进程是交替执行的,很有可能出现PPT还没存完,Word又往队列中存储,造成混乱。因此需要设计一种机制来控制进程切换的时机,即:当第一个进程完成时才能切换下一个进程。从上述可以抽象出来一个“生产者-消费者”模型,如下:

while(true){	//生产者进程
	while(counter == BUFFER_SIZE){;}	//BUFFER_SIZE代表缓冲区大小
	buffer[in] = item;	//存入数据
	in = (in+1)%BUFFER_SIZE;
	counter++;	//计数器加1
}
while(true){	//消费者进程
	while(counter == 0){;}	//当缓冲区不为空时,读出数据
	item = buffer[out];
	out = (out+1)%BUFFER_SIZE;
	counter--;	//计数器减1
}
//其中,counter++ 在汇编中的实际过程为:
register = counter;
register = register+1;
counter = register;

假如初始状态:counter = 5,那么该执行过程描述为下图。理论上来讲,生产者使得 counter+1,而消费者使得 counter-1,因此完整执行一遍生产者和消费者之后 counter 应该不变,但由于二者交替执行,因此导致了 counter的混乱。

一种解决的办法是:在生产者执行的时候给 counter 上锁,如果进程想要切换到消费者,首先检查是否上锁,如果上锁则该时刻不能切换,否则可以切换。优化后的执行过程如下:

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值