- 临界资源和临界区
同一时刻仅允许一个进程使用的共享资源就是临界资源,进程中访问临界资源的那段程序就是临界区。例如,在生产者消费者模型中,一个进程往一个消息队列里面存取内容,这个队列就是临界资源,为了往队列写入任务或从队列取出任务时保护数据安全而为消息队列加锁,从加锁到释放锁的这段代码就是临界区。
- 进程间关系
互斥:多个并发进程需要共享临界资源时,宏观或微观上一段时间内进程只能交替使用这个资源,而不能共享这个资源,我们称多个进程互斥访问资源。
同步:多个并发进程合作完成一个任务的过程中,不同进程的子任务是相互依赖的,让无序的进程(异步性)按指定顺序完成各自的任务从而完成整体任务就是同步。
同步的需求,是因为多个并发进程需要协作按一定工作次序完成某一任务。
通信:进程通信即进程之间交换信息。
其实说的直白点,互斥是指让并发进程同一时刻只能有一个进程进入到临界区使用临界资源,其他进程必须等待直到正在使用资源的进程释放资源;同步是指让并发进程按照指定顺序执行一个任务(某个进程先执行完某个工作,另一个进程才能执行另一个不同的工作),我们要知道按顺序执行一个任务在串行下是很容易实现的,但并发下,进程的执行是无序的,如何让无序的进程按用户规定的顺序执行某任务就是同步要做的事情。
简单来说,互斥就进程间竞争,同步是进程间协作。通信与互斥和同步不是并列关系,而是一个有交集的关系,因为互斥和同步或多或少的都会涉及到进程间的通信。同步是协作关系,互斥是竞争关系,通信是信息交换。
- 进程的通信
进程通信即进程之间交换信息。为了保证数据安全,进程不能直接访问另一个进程的内存地址,因此OS提供了一些安全通信的方式。
进程通信的方式
1、共享内存
共享内存是在内存分配一块空间作为多个通信进程的共享存储区,需要通信的多个进程把共享存储区附加到自己的地址空间就可以对共享存储区读写(其实是将共享存储区扩展到进程自己的逻辑空间,共享存储区的页加入到本进程的页表中,如果进程A和B共享内存区X,可能X在A和B的逻辑地址不同,页号也不同,但是对应的块号肯定是相同的)。
共享内存有 “基于数据结构的共享” 和 “基于存储区的共享” 两种。
基于数据结构的共享 是指 操作系统分配一个指定长度和数据结构的共享空间用于多进程通信。例如共享空间只能放一个长度为10的数组,该方式速度慢、限制多,是一种低级通信方式。
基于存储区的共享 是指 操作系统分配一个共享存储区,其数据的形式、存放位置都有用户进程控制,而非操作系统,是一种高级通信方式。
多个进程对共享空间的访问是互斥的,通过操作系统提供的互斥工具实现互斥,因此进程间共享需要系统介入,相比同一进程的线程间通信代价高。
2、管道通信
管道是用于连接读写进程的一个共享文件(又称pipe文件),其本质是OS在内存中开辟的一个大小固定的缓冲区(通常为一个内存页大小,约为4K)。读写进程可以通过该共享文件传递数据。
管道特征如下:
a. 管道采用半双工通信,某一时间段内只能实现单向传输(进程1->进程2 和 进程2->进程1都可以发生,但不能同时发生)。如果要实现双向同时通信,则需要设置两个管道。
b. 各进程要互斥的访问管道,这意味着:单生产者和单消费者使用管道时,写进程写的时候,读进程不能读,必须写完之后,写进程释放管道,读进程才能从管道读;多生产者和单消费者使用管道时,写进程A写的时候,写进程B不能往管道写入,因此管道内不会出现A和B数据交错的情况,这个管道是进程安全的。
c. 数据以字符流的形式写入管道。管道写满时,写进程执行write()系统调用会阻塞进程,直到管道有空间写入;管道读空时,读进程执行read()系统调用会阻塞进程,直到管道有数据到来;
这其实是管道的同步功能。
d. 如果没写满,则不允许读;如果没读空,就不允许写。(必须写满/读空管道,写/读的进程才会释放管道)
e. 数据一旦被读出,就会被管道抛弃,即数据只能被消费一次,读进程最多只能有1个。如果有多个读进程,可能会发生读错数据的情况(一个进程A读到数据,进程B读不到,或者进程B以为自己读到了和A一样的数据,但其实读到了别的数据)。
f. 管道会确认通信双方是否存在,如果有一方不存在,则不会开始通信。
综上,其实管道同时提供了互斥和同步的功能,来实现安全通信。
3、消息传递
即 进程间的数据以格式化的消息为单位,通过OS提供的 “发送消息send/接收消息receive” 两个原语进行数据交换。
消息头包括:发送进程ID,接收进程ID,消息类型,消息长度等格式化的信息。
消息传递有直接通信方式和间接通信方式这2种。
直接通信方式是将消息直接挂在接收进程的消息缓冲队列上。
间接通信方式是先将消息发送到中间实体(又称信箱)中,接收方再从信箱中获取发给自己的消息,因此也成为“信箱通信方式”。
进程互斥
互斥是指多个并发进程共享临界资源时,操作系统或用户程序组织多个并发进程交替的访问资源,不能同时访问。
对临界资源的互斥访问,在逻辑上分为4个过程:进入区、临界区、退出区和剩余区。
临界区是进程访问临界资源的代码段。
进入区和退出区是负责实现互斥的代码段。进入区负责检测资源是否空闲+对资源上锁,退出区负责对资源解锁。
进程互斥需要遵循 空闲让进、忙则等待、有限等待和让权等待 的原则。
1、空闲让进:临界区空闲(临界资源空闲)时,允许一个请求进入临界区的进程立刻进入临界区。
2、忙则等待:如果已经有进程进入临界区,其他试图进入临界区的进程会被阻塞,等待临界区被释放。
3、有限等待:保证处于等待临界区的进程在有限时间内进入临界区,不会一直等待(不会饥饿)。
4、让权等待:等待临界区的进程必须立刻释放CPU,防止进程忙等。
进程互斥有软件和硬件两种实现方法。