操作系统原理与设计(5)进程控制和进程通信
本系列笔记整理自 https://www.bilibili.com/video/BV1YE411D7nH
个人认为讲解比较清晰,容易理解。
一、进程控制
1.1 什么是进程控制
进程控制的主要功能是对系统中所有进程实施有效管理,它具有创建新进程,撤销已有进程,实现进程状态转换等功能。简而言之,进程控制就是要实现进程状态转换。
1.2 如何实现进程控制
进程控制主要是通过“原语”实现的。原语是一种特殊的程序,它的执行具有原子性。也就是说,这段程序的运行必须一气呵成,中间不能存在中断。
为什么进程控制的过程要“一气呵成”呢?如下图,假设我们需要将一个 PCB 的状态由 2 变成 1。中间至少需要做两件事:(1)将 PCB 的状态值设为 2;(2)将 PCB 从阻塞队列放到就绪队列。如果中间完成第一步后,因为中断而导致程序暂停,就会出现 PCB 明明状态值为 1,却处于阻塞队列的情况。显然,这是不符合我们预期的行为。因此,原语的不可中断性就非常重要了!

1.3 如何实现原语的“原子性”
原语的原子性可以用“关中断指令”和“开中断指令”这两个特权指令实现原子性。
CPU在执行了关中断指令后,就不再例行检查中断信号,直到执行开中断指令之后才会恢复检查。这样,关中断、开中断之间的这些指令序列就是不可被中断的,这就实现了“原子性”。
同时,正是因为这两条指令的特殊性,它们必然不能被用户程序所调用,否则就会造成某个用户程序一直霸占 CPU 执行的情况,这非常危险!
1.4 进程控制相关的原语
1.4.1 进程的创建

1.4.2 进程的终止

1.4.3 进程的阻塞和唤醒

1.4.4 进程的切换

二、进程通信
2.1 什么是进程通信
进程间通信(IPC)是指两个进程之间产生数据交互。比如说:将微博中的内容分享到微信中,这就是一个进程间通信。
2.2 为什么进程通信需要操作系统支持
进程是分配系统资源的单位(包括内存地址空间),因此各进程拥有的内存地址空间相互独立。否则一个进程就可以随意修改其它进程的数据,这是非常危险的!

那么,如果两个进程之间需要进行数据交互,为了保证安全,就需要操作系统的支持。
2.3 共享存储
在内存中,某一个进程 P 可以申请一块共享存储区。其它进程可以通过申请访问这块地址空间从而交互数据。
由于共享存储区中的数据可以被许多进程修改,因此,为避免出错,应该要求各个进程对共享空间的访问是互斥的,即同一时间,只有一个进程修改共享空间的数据。
这种共享方式称为基于存储区的共享,其中数据的形式、存放的位置都是由通信进程控制,而不是操作系统。这种共享方式速度很快,是一种高级通信方式。但有时共享是基于数据结构的共享。比如说,共享空间里只能放一个长度为 10 的数组。这种共享方式速度慢、限制多,是一种低级通信方式。
2.4 消息传递
进程间的数据交换以格式化的消息为单位。进程通过操作系统提供的“发送消息/接收消息”两个原语进行数据交换。
什么是格式化的消息呢?这样的消息包括:消息头和消息体组成。消息头包括:发送进程 ID,接收进程 ID,消息长度等格式化的信息。
消息传递也分为直接通信方式和间接通信方式。直接通信方式要指明接收进程的 ID;间接通信方式通过“信箱”间接地通信,因此又称“信箱通信方式”。
2.5 管道通信
这是一个非常形象的描述。一个进程 P 可以往管道的一侧写数据,而另一个进程 Q 则从管道另一侧读数据。整个过程是单向运输数据的!(毕竟不可能一个管道中既有向右的水流,又有向左的水流)
这里的“管道”实际上是一个特殊的共享文件,又名 pipe 文件。其实就是在内存中开辟一个大小固定的内存缓冲区,数据是先进先出的。
我们需要注意的是(1)管道只能采用半双工通信,某一时间段内只能实现单向传输。如果要实现双向同时通信,则需要设置两个管道。(2)各进程要互斥地访问管道。(3)当管道写满时,写进程将被阻塞,直到读进程将管道中的数据取走。(4)当管道读空时,读进程将被阻塞,直到写进程往管道中写入数据。(5)管道中的数据一旦被读出,就彻底消失。允许有多个写进程,多个读进程,但读进程必须轮流读数据。
【注】考试的话最好要一个管道允许多个写进程,一个读进程。这是408真题的一个答案所提及的。