操作系统系列 -- 进程间通信

817 阅读5分钟

什么是进程间通信

进程间通信(Inter-Process Communication),简称 IPC,意思就是在不同进程之间传递信息。它是一组编程接口,让程序员协调不同进程,使能够相互传递消息

进程间通信的意义

(1)数据传输:一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几兆字节之间。
(2)事件通知:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。
(3)数据共享:多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到。
(4)资源共享:多个进程之间共享同样的资源。为了作到这一点,需要内核提供锁和同步机制。
(5)进程控制:有些进程希望完全控制另一个进程的执行(如 debug 进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。

进程间通信方式

管道

单工,半双工,全双工

  • 单工:数据传输是单向
  • 半双工:它可以在一个信号载体的两个方向上传送,但不能同时传送
  • 全双工:可在信号载波的两个方向同时传输

匿名管道

两个限制:① 单工:同时只能单向传输数据;② 只能在父子和兄弟进程之间传输数据

父子进程之间的通信三部曲:(由于 fork 的原因只能在父子和兄弟之间

命名管道

打破匿名管道的两个限制,实现:① 半双工:可以双向传输(但没法同时双向,全双工才可以);② 由于有了名字,支持任意多个进程间通讯

标识符:每个内核的 IPC 结构(消息队列、信号量或共享内存)都用标识符(一个非负整数)引用。

:由于标识符是 IPC 对象的内部名,所以为了是多个进程间能够访问到同一 IPC 对象,需要提供一个外部名。即键(key),。键和标识符之间存在一一映射的关系,分别存在管道中和 IPC 对象内部。(因为有键值的存在所以可以在任意多个进程之间通信

·

信号量

信号量的本质就是一个计数器,用来实现进程之间的互斥与同步

比如某个资源只能同时被 5 个进程共享,那么每多一个进程去访问这些资源,则计数器加 1,每当某个进程结束该资源的访问,则计数器减 1。如果达到满,则暂停其他进程对该资源的访问。

信号量不仅仅用于进程之间的冲突,还用于线程之间的冲突

消息队列

image.png

消息队列是一种异步的通信方式

消息队列是消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。

共享内存

共享内存是所有IPC方式中最快的一种,原因在于:共享内存一旦映射到进程地址空间,进程间数据的传递就不需要涉及内核。

对于管道、FIFO和消息队列,两个进程之间通过这三种方式进行通信,则内核就扮演着“中转站”的角色。

  • 发送消息一方,通过系统调用(write或msgsnd)将消息从用户层拷贝到内核层,由内核暂时保存这份信息;
  • 接受消息的一方,通过系统调用(read或msgrcv)将消息从内核层提取到用户层

注意:在使用read/write时,操作系统还会将数据缓存到临时缓冲区内。

我们在来看共享内存:

多个进程共同访问同一片物理内存的

内核负责构建出一片内存区域,两个或多个进程可以将这块内存区域映射到自己的虚拟地址空间,从此之后内核不再参与双方通信。

注意:建立共享内存之后,内核并不是完全不参与进程间的通信,因为当进程使用共享内存时,可能会发生缺页,引发缺页中断,这种情况下,内核还是会参与进来的。

套接字 Socket

image.png

  1. 服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用 accept 阻塞,等待客户端连接。
  2. 在这时如果有个客户端初始化一个 Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。
  3. 客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束

参考文章