进程
进程的定义
我们都知道,程序的本质,就是一个指令序列。
在早期的计算机里面,它只支持单道程序。
在一个程序运行的时候,他说,cpu是我的!内存是我的!I/O设备也是我的!
然后呢,他把程序段放在内存的低地址区域,把数据段放在高地址区域。
在引入多道程序技术之后,计算机就可以运行多个程序了。
这个时候,内存中就得放好多的程序段,好多的数据段!
此时,程序是并发的执行的,而操作系统的任务就是找到各个程序段,在内存的位置,找到对应的数据段。
所以,为了让操作系统能更好的去管理各个程序,让他们能并发的执行。引入了我们的主角——进程!
系统会为每个运行的程序配置一个数据结构,称为进程控制块(PCB),用来描述程序代码存放的位置
因此,PCB(Process Control Block),程序段,数据段,构成了进程的实体!
因此,我们平时所说的创建一个进程实际上是指,创建进程实体中的PCB,撤销进程实际上是撤销进程实体中的PCB
PCB是进程存在的唯一标志!PCB是进程的管理者,它记录了进程的信息, 进程控制和管理,资源的分配,处理机相关信息
对于进程,比较传统的定义有:
- 进程是程序的一次执行过程
- 进程是一个程序以及其数据在处理机上顺序执行所发生的活动。
讲的很多东西,都不是人话,总结下来就是,这些定义都在强调进程的一个特性——动态性
我们刚刚说了,程序段,数据段,构成了进程的实体。而进程实体是静态的。严格来讲,进程和进程实体不一样。进程是运行起来的进程实体,它是动态的!!
进程的组织
在一个系统中,通常会有上千个PCB,为了进行有效的管理,我们应该用适当的方式把PCB进行管理
进程的组织方式有两种:链接方式和索引方式。
链接方式
链接方式中有3种指针,指向进程的不同的状态。
- 执行指针指向正在执行的进程
- 就绪队列指针指向处于就绪态的进程(通常会有很多,优先级高的在前面)
- 阻塞队列指针指向处于阻塞态的进程。
索引方式
链接的指向指的是队列。而索引的方式指的是索引。两者很类似。
唯一不同的是,索引表还会再指向不同的PCB
进程的特征
-
动态性
进程是程序的一次执行过程,是动态产生,变化,消亡的
-
并发性
内存中有多个进程实体,各个进程并发执行
-
独立性
进程是能独立运行,独立获得资源,接受调度的基本单位
-
异步性
之前我们说过,两个进程争夺一个资源的时候,无法确定抢到速度的快慢,因此它们是按照各自独立,不可预知的速度向前推进的。
-
结构性
每个进程都配置了一个PCB。结构上来看,都是PCB,程序段,数据段
重要考点
- 定义:进程是进程实体的运行过程,是系统进行资源调度和分配的基本单位
- PCB是进程存在的唯一标志,他是进程的管理者
- 程序本身的运行所需要的数据在程序段和数据段
- 动态性:进程最基本特征;独立性:进程是进行资源分配,调度的基本单位
进程的状态和切换
进程的状态——三种基本状态
分为运行态,就绪态,阻塞态。
- 运行态占有CPU,并在CPU上面运行。
- 就绪态具备了运行条件,但是没有空闲CPU,因此在等待(完事具备,只欠CPU)
- 阻塞态因为在等待某个时间暂时不能运行
进程的状态——另外两种状态
我们都知道,一个程序运行的时候,会在内存中创建PCB,程序段,和数据段。
在这个创建的过程,我们就叫他创建态
在进程运行结束(或者遇到一些异常导致进程无法继续进行下去,比如i/0),需要撤销进程,比如回收内存区域,撤销I/O设备的权限
在这个撤销的过程,我们就叫他终止态
因此,进程有5种状态
进程的切换
我们通过一张图,来总体的看一下各个状态的转换。
在创建态完成之后,系统已经做好了准备工作。比如PCB的创建
随机它进入了就绪态,就绪态他拥有了除了处理机以外的其他权限。
随后由于上一个进程的时间片到了,进程被CPU调度,它拥有了处理机的权限!
于是,她就想用系统调用的方式,进入核心态,获得打印机的资源。于是,他就进入了漫长的等待,也就是阻塞态。阻塞状态下,他失去了处理机和其他资源的权限。
等完了以后,申请的资源被重新分配回来了,它又回到了就绪态,此时它又拥有了除了处理机以外的其他权限。
然后它被调度,进入运行态。
程序运行结束了,或者遇到异常了,它进入终止态,从cpu中回收资源,撤销PCB
我们发现,从运行态到阻塞态,是主动申请资源的过程,是主动的
而从阻塞态到就绪态,是等待资源响应的过程,是被动的
进程的控制
基本概念
进程控制简单理解,就是实现刚刚说的5种进程状态的转换
如何实现?
我们知道,操作系统会将很多PCB挂到相应状态的队列当中。
-
创建态——>就绪态
需要修改PCB内容进入就绪队列。
-
就绪态——>运行态
需要恢复程序运行环境(之前可能没执行完,没到终止态),修改PCB内容和相应队列
-
运行态——>就绪态
这是进程切换了,比如进程3切换到进程1,需要修改PCB内容,将他放进阻塞队列
-
阻塞态——>就绪态
需要修改PCB内容,将他放进就绪队列。如果等待资源,还需要给进程分配系统资源
-
运行态——>终止态
回收资源,撤销PCB
思考一个问题,如果说一个进程将它从一个队列改为另一个队列,但是系统没有改PCB里面的状态标志(PCB的内容)。
这种情况很危险,有可能导致系统错误!!
为了防止这个问题,采用了原语
什么是原语?
原语的特点就是不允许中断,一气喝成。
学过多线程的同学也知道,这其实是原子操作
那原语的本质又是啥呢?
原语采用“开中断”,“关中断”指令实现。
在“开中断”,“关中断”之前的操作,不会被外部中断信号打断。
既然它这么牛,其实我们也可以想到,这是操作系统在核心态中执行的特权指令。
既然说到特权指令,那我们不得不再复习一下操作系统的内核了。
操作系统内核:时钟管理,中断管理,原语,对系统资源的管理(进程管理,存储器管理,设备管理)
进程相关的原语
本质:进程控制会导致进程状态的转换。无论哪个原语,要做的无非3件事情:
1.更新PCB信息(如修改进程状态标志,将运行环境保存到PCB,从PCB中恢复运行环境)
- 所有的进程控制原语就一定会修改进程状态标识
- 剥夺当前运行的CPU之前,就一定得保存其运行环境
- 某进程开始运行前,需要恢复运行期环境
2.将PCB插入合适队列
3.分配/回收资源
进程通信
什么是进程通信?
顾名思义,其实进程通信就是指进程之间的信息交换
进程是系统分配资源的单位,因此各进程拥有的内存地址空间相互独立。
为了保证安全,一个进程不能直接访问另一个进程的地址空间。
但是进程之间的信息交换又是必须实现的,为了保障进程间的通信,操作系统提供了一些方法
进程通信——共享存储
我们可以再内存中设置一个共享空间。供两个进程来访问。
这两个进程对共享空间的访问必须是互斥的。
进程通信——管道通信
管道是用于连续读写进程的一个共享文件,其实就是再内存中开辟一个大小固定的缓冲区
但由于上图,我们发现,管道只能采用半双工通信,某一时间段只能实现单向的传输。但如果实现双向同时通信,则需要设置两个管道。
各个进程对于管道的访问也是需要互斥的进行的
管道通信的具体流程:进程1 往管道内部写入数据,当管道写满的时候,写进程的write()系统调用将会被阻塞,等待读进程将数据取走。当都进程将数据全部取走以后,此时读进程的read()系统调用将会被阻塞。
注意:如果没有写满,不允许读。如果没有读完,不允许写;
并且数据一旦读出,就从管道内被抛弃了。这意味着读进程最多只能有一个,否则会有读错的情况
进程通信——消息传递
进程间的数据交换以格式化的消息,(Message)为单位。进程通过操作系统提供的 “发送消息/接受消息”两个原语进行数据的交换。
一个Message包括消息头和消息体。消息头里面包括进程ID,接受进程id,信息类型,消息长度等格式化信息。
而消息传递有分为两种方式——直接通信,间接通信。
- 直接通信就是将Message挂载到接受消息的进程当中,形成一个队列。
- 间接通信就是在俩进程之间设置一个信箱。从中寄出或者取走信息。(有点像公共存储区域)
重要考点
- 共享存储需要互斥的访问空间
- 一个管道只能实现半双工通信(单向)
- 管道通信写满不写,读空不读;没写满不读,没读空不写
- 消息传递的两种方式