进程的状态和转换
进程是程序的一次执行。在这个执行过程中,有时进程正在被CPU处理,有时需要等待CPU服务,显然进程的状态是在不断变化的。为了方便对各个进程的管理,操作系统将进程合理的划分为几种状态
进程的三种基本状态
运行态 Running
占有CPU,并在CPU上运行。
单核处理器下,同一时刻最多只有一个进程处于运行态,双核环境下可以有两个进程处于运行态
就绪态 Ready
已经具备运行条件,但由于没有空闲CPU,而暂时不能运行
注意这里所说的具备运行条件是指进程已经拥有了除CPU以外的所有需要的资源,包括所需要的设备的控制权限,缺少的只有CPU的控制权
阻塞态 Waiting/Blocked
又称等待态,因等待某一事件而暂时不能运行
例如,等待操作系统分配打印机的控制权限,读取磁盘操作的请求等。CPU是计算机中最昂贵的不见,为了提高CPU利用率,需要先将其他进程所需资源分配到位,才能得到CPU服务
进程的另外两种状态
创建态 New
也称新建态,进程正在被创建,操作系统为进程分配资源,初始化PCB的阶段
终止态 Terminated
进程正在从系统中撤销,操作系统回收进程拥有的资源,撤销PCB
可能是由于进程运行结束,也可能是由于bug导致进程无法继续执行(例如数组越界或数学错误)
进程状态的转换
进程控制
进程控制的主要功能是对系统中的所有进程实施有效的管理,它具有创建新线程,撤销已有线程,实现线程状态转换等功能
简言之,进程控制就是要实现进程各个状态之间的转换
如何实现进程控制
原语
原语的特点是执行期间不允许中断,只能一次全部执行完成。这种不可中断的操作也称原子操作。
原语采用“关中断指令”和“开中断指令”实现。代码执行前执行关中断指令,所有代码执行结束后执行开中断指令,在此期间,外部的中断信号会被忽略,待开中断指令执行后,再开始处理传来的外部中断信号,由此保证了原语的执行特点
显而易见,关中断/开中断指令的权限十分大,二者都是只允许在核心态下执行的特权指令
原语可能进行的三类事情
- 更新PCB中的信息(例如修改进程状态标志,将运行环境保存到PCB,从PCB恢复运行环境)
- 所有进程控制原语一定会修改进程状态标志(因为所有进程控制原语一定修改进程状态)
- 剥夺当前运行进程的CPU使用权必然需要保存其运行环境(为后续该进程重新进入运行态,恢复运行环境准备)
- 某进程开始运行前必然要恢复运行环境(利用之前保存在PCB中的环境)
- 将PCB插入合适的队列(进程组织)
- 分配/回收资源
进程的创建
无->创建态->就绪态
创建原语
- 申请空白PCB
- 为新进程分配所需资源
- 初始化PCB
- 将PCB插入就绪队列
引起进程创建的事件
- 用户登录:分时系统中,用户登陆成功,系统为其建立一个新进程
- 作业调度:多道批处理系统中,有新作业放入内存,会为其创建新进程
- 提供服务:用户向操作系统提出某些请求,会新建进程处理该请求
- 应用请求:用户主动请求创建一个子进程
进程的终止
就绪态/阻塞态/运行态->终止态->无
撤销原语
- 从PCB集合中找到所有终止进程的PCB
- 若进程正在运行,立即剥夺CPU,将CPU分配给其他进程
- 终止其所有子进程
- 将该进程拥有的所有资源归还给父进程或操作系统
- 删除PCB
引起进程终止的事件
- 正常结束
- 异常结束(例如进程执行中出现bug)
- 外界干预(例如进程执行中手动通过任务管理器直接关闭进程)
进程的阻塞和唤醒
阻塞原语 运行态->阻塞态
- 找到要阻塞的进程对应的PCB
- 保护进程运行环境,将PCB状态信息设置为阻塞态,暂停进程运行
- 将PCB插入相应事件的等待队列
引起阻塞的事件
- 需要等待分配某种资源
- 需要等待相互合作的其他进程完成工作
唤醒原语 阻塞态->就绪态
- 在等待事件队列中找到PCB
- 将PCB从等待队列移除,设置进程为就绪态
- 将PCB插入就绪队列,等待被调度
引起进程唤醒的事件
- 等待的事件发生
阻塞原语和唤醒原语必须成对出现
进程的切换
运行态->阻塞态/就绪态
就绪态->运行态
切换原语
- 将运行环境信息保存在PCB中
- PCB移入相应队列
- 选择另一个进程执行,并更新其PCB
- 根据PCB恢复新进程所需的运行环境
引起进程切换的事件
- 当前进程的时间片结束
- 有更高优先级的进程到达
- 当前进程主动阻塞
- 当前进程终止
进程通信
进程通信指进程之间的信息交换
进程是系统分配资源的单位(包括内存地址空间),因此各个进程拥有的内存地址空间相互独立,为了保证系统安全,一个进程不能直接访问另一个进程的地址空间。
但是有时进程之间的信息交换又是必须实现的,为了保证进程间的安全通信,操作系统提供了多种方法进行进程间的通信
- 共享存储
- 消息传递
- 管道通信
共享存储
两个进程都不能直接访问对方的地址空间,所以两个进程在内存中开辟出一块共享空间用于通信。
两个进程对共享空间的访问必须是互斥的,即A在访问共享空间时,B不可以访问(互斥访问通过操作系统提供的工具实现,即同步互斥工具,如P,V操作)
共享存储又分为以下两种
基于数据结构的共享
共享空间里只能存放提前规定好的某种数据结构(例如长度为10的数组),这种方式共享的速度慢,对共享数据的限制多,是一种低级通信的方式
基于存储区的共享
在内存中画出一块共享存储区。数据的形式,存放位置由进程控制,而不再是操作系统,相较于前一种速度更快,是一种高速通信方式
管道通信
管道是指用于连续读写进程的一个共享文件,又名pipe文件,其实就是在内存中开辟一个固定大小的缓冲区
注意
- 管道只能采用半双工通信,即某一时间段内只能实现单向的传输,如果要实现双向同时通信,则需要设置两根管道
- 各进程仍然需要互斥的访问管道
- 写进程将数据以字符流的形式写入管道,管道写满后,写进程的write系统调用将被阻塞,等待读进程读取所有数据,当读进程读取所有数据后,管道变空,此时读进程的read系统调用将被阻塞
- 如果管道没写满,就不允许读,如果管道没读空,就不允许写
- 数据一旦被读出,就从管道中被抛弃,没有备份,这就意味着读进程最多只能有一个,防止读错数据的情况发生
消息传递
进程间的数据交换以格式化的信息(Message)为单位。进程通过操作系统提供的“发送消息/接收消息”两个原语进行数据交换
直接通信方式
A进程通过发送原语向B进程发送消息,B进程利用接收原语接收信息,并将消息挂到本进程的消息缓冲队列上,逐个读取消息缓冲队列的消息
间接通信方式
消息不直接在两个进程间传递,而是首先由发送方通过发送原语发送到中间实体(信箱)中,然后接收方利用接收原语找到信箱中发给自己的信息。所以该种通信方式也称“信箱通信方式”