目录
一、进程间的通信?
二、为什么进程间通信需要操作系统支持?
三、进程间通信的方法
3.1 共享存储
3.2 消息传递(消息队列)
3.2.1 直接通信方式【点名道姓的消息传递】
3.2.2 间接通信方式【以“信箱”作为中间实体进行消息传递】
3.3 管道通信(FIFO)【读写数据自由度没有共享内存方式高】
四、总结
一、进程间的通信?
进程通信是指进程之间的信息交换。
定义:进程间通信(Inter-Process Communication,IPC)是指两个进程之间产生数据交互。
举例:
二、为什么进程间通信需要操作系统支持?
进程间通信需要操作系统支持的原因:
进程间通信(Inter-Process Communication,IPC)需要操作系统的支持,主要是因为进程具有隔离性,操作系统通过一系列机制保护各个进程的独立性和安全性。因此,直接共享数据或直接访问其他进程的内存空间是被禁止的。操作系统作为管理资源和提供服务的核心组件,负责为进程间通信提供安全、高效的机制。
以下是操作系统支持进程间通信的主要原因:
1. 进程的隔离性
- 操作系统为每个进程分配独立的虚拟地址空间,以防止一个进程访问或修改另一个进程的内存。这种隔离性是操作系统为确保系统稳定性和安全性所采取的基本措施。
- 在这种隔离性下,进程不能直接访问彼此的内存,因此,操作系统必须提供某种机制,使得进程可以在受控的情况下相互传递信息,而不破坏这种隔离。
2. 资源管理和共享
- 进程共享系统资源(如内存、文件、设备等),这些资源的访问和管理需要操作系统的协调。例如,如果两个进程要共享同一个文件,操作系统需要提供一种安全的机制来确保文件的正确读写,不会因并发操作而导致数据损坏。
- 操作系统通过进程间通信机制,如管道、消息队列、共享内存等,使多个进程能够高效、安全地共享资源。
3. 数据同步与一致性
- 在并发执行的进程中,多个进程可能需要同步访问同一个数据或资源。为避免竞争条件(race condition)和数据不一致问题,操作系统需要提供同步机制,如信号量、互斥锁等,来确保进程间的同步操作。
- 操作系统通过这些同步机制,控制进程对共享资源的访问,防止死锁、数据损坏或不一致性。
4. 跨进程通信的安全性
- 操作系统为进程提供了隔离的执行环境,防止进程之间的恶意访问或篡改。为了确保进程间通信的安全性,操作系统必须对通信操作进行监控和管理,确保只有被授权的进程才能相互通信,防止信息泄露或恶意破坏。
- 通过操作系统的权限管理,只有符合权限要求的进程才能使用特定的通信机制。
5. 进程的生命周期管理
- 操作系统负责管理进程的创建、执行、挂起、终止等生命周期。进程间通信机制与进程的生命周期密切相关。例如,父进程和子进程之间可能需要通过管道或信号进行通信,操作系统需要协调这些通信机制,确保信息在正确的时刻被传递和处理。
- 操作系统还需要处理进程异常终止的情况,确保通信数据不会因进程退出而丢失或混乱。
6. 跨平台和跨网络通信
- 操作系统不仅支持本地进程间的通信,还支持跨网络的进程通信。例如,分布式系统中,不同主机上的进程需要通过网络进行通信。操作系统需要提供网络通信的基础设施,如套接字(Socket),来实现这种进程间的远程通信。
- 操作系统通过统一的接口(如TCP/IP协议栈)来管理网络通信,确保进程间可以通过网络安全、可靠地传递信息。
7. 高效的通信机制
- 操作系统提供了多种进程间通信机制,适应不同的通信需求。常见的IPC机制包括:
操作系统为这些机制提供底层的实现,确保它们高效且正确地工作。
- 管道(Pipe):用于父子进程间的单向数据通信。
- 消息队列(Message Queue):允许多个进程之间通过消息的形式传递数据。
- 共享内存(Shared Memory):允许进程直接共享内存中的某个区域,实现高速数据传递,但需要同步机制来避免竞争条件。
- 信号量(Semaphore)和互斥锁(Mutex):用于进程间的同步,确保进程对共享资源的互斥访问。
- 信号(Signal):用于进程之间发送简单的通知或中断。
- 套接字(Socket):支持网络间进程通信。
8. 调度与通信的协调
- 进程间的通信涉及数据的发送、接收、缓冲、同步等操作,而这些操作可能会涉及到进程调度。例如,当一个进程在等待另一个进程传递数据时,它可能需要被挂起,直到数据到达。这需要操作系统的调度器协调进程的运行和等待状态。
- 操作系统通过调度算法和进程优先级管理,确保通信过程不会因某些进程的阻塞而影响系统整体性能。
9. 跨体系架构的抽象
- 操作系统为不同平台上的进程提供一致的通信接口,隐藏底层硬件和体系结构的差异。例如,无论在32位还是64位平台上,进程都可以通过相同的系统调用接口进行通信。
- 操作系统的IPC机制使得开发人员不必关心底层硬件实现,可以通过统一的API进行进程间的通信。
总结
进程间通信需要操作系统的支持,因为操作系统负责管理进程的隔离、资源共享、安全性、同步和调度等。通过操作系统提供的IPC机制,进程可以安全、高效地相互通信,并共享必要的资源。操作系统通过这些机制确保并发环境下进程的正确性、稳定性和安全性,同时简化了开发者的工作,使他们无需关注底层细节。
进程是分配系统资源的单位(包括内存地址空间),因此各进程拥有的内存地址空间相互独立。
我们的系统在给进程分配内存地址空间的时候,各个进程的内存地址空间是相互独立的,比如说进行P可以访问进程P的地址空间,进程Q可以访问进程Q的地址空间,但是进程P不可以访问进程Q的地址空间。
这么规定是出于安全的考虑,如果一个进程可以随意访问其他进程的地址空间,那么该进程可以随意修改其他进程的数据,或者随意读取其他进程的数据。我们考虑一件事情,假设说你的手机不知道什么时候安装了一个垃圾软件,这个垃圾软件可以随意地访问你的其他进程的地址空间,那么是不是存在这样一种可能,即这个垃圾软件有可能把你的隐私数据读取走了,那这显然是很危险的、不安全的,因此,出于安全考虑,各个进程只能访问自己的内存地址空间而不能访问其他进程的内存地址空间。
那么如果两个进程要进行信息的交互,即进程之间通信,那么显然进程P是不可能直接把数据写到进程Q的内存地址空间的。
由于进程不可以直接访问其他进程的地址空间,因此必须要有操作系统的支持才可以完成进程间的通信。
那么在操作系统的支持下,进程之间应该如何进行通信呢?
接下来我们介绍三种方法:共享存储、消息传递、管道通信。
三、进程间通信的方法
3.1 共享存储
在共享存储器系统(Shared-Memory System)中,相互通信的进程共享某些数据结构或共享存储区,进程之间能够通过这些空间进行通信。据此,又可把它们分成以下两种类型: (1) 基于共享数据结构的通信方式。 (2) 基于共享存储区的通信方式。
基于存储区的共享: 操作系统在内存中划出一块共享存储区,数据的形式、存放位置都由通信进程控制,而不是操作系统。这种共享方式速度很快,是一种高级通信方式。 如下图所示:
基于数据结构的共享: 比如共享空间里只能放一个长度为10的数组。这种共享方式速度慢、限制多,是一种低级通信方式。如下图所示:
3.2 消息传递(消息队列)
消息队列是什么?
消息队列(Message Queue) 是一种进程间通信(IPC)机制,允许进程通过操作系统传递消息。消息队列的主要功能是使一个进程发送消息,另一个进程从队列中接收这些消息。这是一种异步通信方式,进程可以在不同时间发送和接收消息。
消息队列由操作系统维护,与文件类似,通常有一个唯一的消息队列ID。进程通过该ID来访问消息队列。
在该机制中,进程不必借助任何共享存储区或数据结构,而是以格式化的消息 (message)为单位,将通信的数据封装在消息中,并利用操作系统提供的一组通信命令(原语),在进程间进行消息传递,完成进程间的数据交换。
基于消息传递系统的通信方式属于高级通信方式,因其实现方式的不同,可进一步分成两类: (1) 直接通信方式 (2) 间接通信方式。
3.2.1 直接通信方式【点名道姓的消息传递】
假设现在进程P要给进程Q发送一个消息,在操作系统的内核区域,管理着各个进程的PCB,PCB间接管理该进程的消息队列,如下图所示:
PCB与消息队列的关系
进程间通信(IPC)是一种在进程之间传递数据的机制,消息队列就是其中一种常用方式。在内核中,消息队列通常由内核管理,并通过 PCB 进行间接的引用和操作:
PCB 间接管理消息队列:
- 操作系统内核维护着消息队列的全局列表或者表格,进程的 PCB 中会保存指向该消息队列的标识符或指针。
- 当进程需要访问消息队列时,PCB 中的这些信息会被操作系统使用,以找到对应的消息队列资源。
消息队列的管理:
- 每个消息队列有一个唯一的标识符 (比如消息队列 ID),进程通过该标识符进行通信。
- PCB 记录了该进程所拥有或使用的 IPC 资源,包括消息队列。
- 当一个进程终止时,操作系统根据 PCB 中的资源信息清理与该进程相关联的消息队列。
调度和资源分配:
- PCB 还用于调度器在调度过程中跟踪进程的通信状态。如果一个进程处于等待某个消息的状态,它的 PCB 会反映出这种状态,进而影响进程的调度。
首先,进程P要在自己的地址空间中来完善消息,最终形成格式化消息msg,如下图所示:
接下来进程P会使用到发送原语【send(Q ,msg)】,指明消息msg是要发送给Q的。 该发送原语会导致操作系统内核接收到这个格式化消息msg,并且会将msg挂在进程Q的消息队列中,也就是说,消息体msg从进程P的地址空间复制到了内核空间。如下图所示:
进程Q使用接收原语receive(P,&msg)接收P进程发送的msg,进程Q执行接收原语之后,操作系统内核会检查进程Q的消息队列中由P进程发送过来的消息,操作系统内核会把这个消息体从操作系统的内核区给复制到进程Q的地址空间。如下图所示:
3.2.2 间接通信方式【以“信箱”作为中间实体进行消息传递】
假设进程P和进程Q现在要通信,进程P可以通过系统调用向操作系统申请一个“邮箱”,那如何通过“邮箱”使得两个进程之间完成通信呢?
进程P在自己的地址空间中完善消息,形成格式化消息msg,如下图所示:
进程P使用发送原语send(A,msg)来指明往信箱A发送消息msg,如下图所示:
进程Q使用接收原语receive(A,&msg)从信箱A接收信息,如下图所示;
可以多个进程往同一个信箱send消息,也可以多个进程从同一个信箱中receive消息。
3.3 管道通信(FIFO)【读写数据自由度没有共享内存方式高】
定义:管道是一种将数据从一个进程传递到另一个进程的通信机制。数据从管道的一端(写入端)输入,然后从另一端(读取端)读取。
所谓“管道”,是指用于连接一个读进程和一个写进程以实现它们之间通信的一个共享文件,又名pipe文件。向管道(共享文件)提供输入的发送进程(即写进程)以字符流形式将大量的数据送入管道;而接受管道输出的接收进程(即读进程)则从管道中接收(读)数据。由于发送进程和接收进程是利用管道进行通信的,故又称为管道通信。这种方式首创于UNIX系统,由于它能有效地传送大量数据,因而又被引入到许多其它操作系统中。
为了协调双方的通信,管道机制必须提供以下三方面的协调能力:
① 互斥【由操作系统实现】,即当一个进程正在对pipe执行读/写操作时,其它(另一)进程必须等待。
② 同步,指当写(输入)进程把一定数量(如4 KB)的数据写入pipe,便去睡眠等待,直到读(输出)进程取走数据后再把它唤醒。当读进程读一空pipe时,也应睡眠等待,直至写进程将数据写入管道后才将之唤醒。【写进程往管道写数据,即便管道没被写满,只要管道没空,读进程就可以从管道读数据;读进程从管道读数据,即便管道没被读空,只要管道没满,写进程就可以往管道写数据】
③ 确定对方是否存在,只有确定了对方已存在时才能进行通信。
“管道”是一个特殊的共享文件,又名pipe文件。其实就是在内存中开辟一个大小固定的内存缓冲区。
管道只能采用双工通信,某一时间段内只能实现单向的传输。如果要实现双向同时通信,则需要设置两个管道。
管道中的数据一旦被读出,就彻底消失。因此,当多个进程读同一个管道时,可能会错乱。对此,通常有两种解决方案:①一个管道允许多个写进程,一个读进程(2014年408真题高教社官方答案)﹔②允许有多个写进程,多个读进程,但系统会让各个读进程轮流从管道中读数据(Linux的方案)。