现代操作系统 原理与实现(银杏书)—— 进程间通信

进程间通信 (IPC)

7.1 基础概念

简单IPC概念

  • IPC至少需要两个进程参与: 一个发送者,一个接收者
  • 内核为两个进程映射了一段共享内存内存
  • 一种常见的通信数据的抽象——消息
三种对比:共享内存 VS 基于共享内存的消息传递 VS 操作系统辅助的消息传递
  • 共享内存
    • 直接在两个进程间建立共享区域,进程可以直接使用该共享区域上的数据,不存在“消息”的抽象
    • 共享内存理论上讲,可以实现零内存拷贝的传输,性能好
  • 基于共享内存的消息传递
    • 操作系统在通信过程中不干预数据传输
    • 多了“消息”的抽象
    • 消息传递的基本接口:
      • 发送消息
      • 接收消息
      • 远程过程调用
      • 回复消息
  • 操作系统辅助的消息传递
    • 内核对用户态提供通信的接口
    • 缺点:
      数据需要经过两次拷贝:
      • 从发送者用户态内存拷贝到内核内存
      • 从内核内存拷贝到接收者用户态内存
    • 优点:
      1. 抽象更简单
      2. 安全性保证更强,不会破坏发送者和接收者进程的内存隔离性
      3. 在多方通信时,多个进程间共享内存区域复杂且不安全,操作系统辅助传递可以避免此问题
同步IPC和异步IPC
  • 同步IPC指他的IPC操作(如send)会堵塞进程直到该操作完成
    • 同步IPC往往是双向IPC(或RPC),即发送者需要等待返回结果
  • 异步IPC通常是非堵塞的,进程只要发起一次操作即可返回,而不需要等待其完成
    • 异步IPC通常通过轮训内存状态或注册回调函数(如果内核支持)来获取返回结果

同步 VS 异步

堵塞 VS 非堵塞

通信连接管理
  • 直接通信
    • 通信的进程一方需要显示地标识另一方
  • 间接通信
    • 需要经过一个中间的信箱来完成通信
    • 每个信箱有自己唯一的标识符,而进程间通过共享一个信箱来交换消息
权限检查
  • 进程间的通信依赖一套权限检查的机制来保证连接的安全性
    • 微内核中,基于Capability的安全检查机制
    • linux这样的宏内核中,将安全机制和文件的权限检查结合在一起
System V 进程间通信权限管理
  • System V进程间通信通常指的是宏内核下三种具体的进程间通信机制:
    1. System V 消息队列
    2. System V 信号量
    3. System V 共享内存
  • 在linux 中,System V 通信的权限管理基于文件的权限检查机制。
  • 在linux内核中负责进程间通信权限管理的IPC_PERM 结构体用来检查“访问模式”。
      	struct ipc_perm {
      		key_t		key;		
      		uid_t		uid;		// owner的uid和gid
      		gid_t		gid;
      		uid_t		cuid;		// creator的uid和gid 
      		gid_t		cgid;
      		mode_t		mode;		//访问模式
        };
    



7.2 宏内核进程间通信

具体包括:管道,System V 中的消息队列,信号量,共享内存,Linux信号机制,套接字机制

  • 宏内核操作系统中进程间通信更多的是应用之间的交互,设计的重心通常会放在接口的易用性、稳定性等方面。
1. 管道进程间通信
  1. 管道是单向的IPC,内核中通常有一定的缓冲区来缓冲消息。
  2. 管道通信的数据是字节流,需要用户自己对数据进行解析。
  3. 管道用于两个进程之间的消息传递。
  4. 具体实现:
    (1) 管道在UNIX系列的系统中会被当做一个文件,它的创建会返回一组(两个文件描述符)
    (2) 不过管道实际上不会使用存储设备,而是使用内存作为数据的一个缓冲区
  5. 管道的行为是FIFO的。
命名管道和匿名管道
  • 匿名管道
    • 通过pipe系统调用创建
    • 问题:
    • 只能通过fork继承的方式建立父子之间的连接,对于其他进程间无法使用
  • 命名管道
    • 通过mkfifo系统调用来创建
    • 创建过程中会指定一个全局的文件名(例如 /tmp/namedpipe),通过这种方式,两个进程通过同一个相同的管道名就可以进行通信
2. System V 消息队列
  1. 消息队列是唯一一个以消息(内核提供的)为数据抽象的通信方式。
消息队列的结构
  • 当创建新的消息队列时,内核从系统内存中分配一个队列数据结构,作为消息队列的内核对象。
  • 包括:
    • 消息头部指针,指向消息队列,同时包含IPC_PERM(消息权限)
    • 消息,链表结构的队列,消息包含两部分:类型和数据
基本操作
  1. msgget
    获取已有消息队列的连接或者创建新的消息队列
  2. msgsnd
    往消息队列上发送消息
  3. msgrcv
    从队列接收消息
  4. msgctl
    控制和管理一个消息队列(如修改消息队列的权限或删除一个消息队列)
linux内核实现
  • 一个消息队列被创建后,除非内核重启或主动删除,否则其数据会一直保留
  • 消息队列的内存空间是有限制的,建议使用共享内存机制来传递长消息,而非使用消息队列
  • 消息在用户态和内核态之间传递时,会有拷贝的开销
    • 发送消息时,内核通过copy_from_user从用户态搬运到内核空间
    • 接收消息时,内核通过copy_to_user将数据搬回用户态
3. System V 信号量
  1. 信号量在实际的使用中主要用作进程间的“同步”。
  2. 信号量本省能传递的数据量很少,一般来说仅有一个共享的整形计数器,该计数器由内核维护。
信号量进程间通信
  • 信号量的主要操作是两个原语:P 和 V 。
  • P 缩写自荷兰语Probeer(尝试),尝试讲一个计数器减1。
    • P 操作失败会将当前进程切换到堵塞状态,直到其他进程执行了 V 操作
  • V 缩写自荷兰语Verhoog(增加),将一个计数器加1。
    • V 操作可能会唤醒一个因 P 操作而陷入堵塞的进程
4. System V 共享内存
  1. 共享内存的一个很重要原因是性能
共享内存进程间通信
  • 一个或多个进程在其所在的虚拟地址空间中映射相同的物理内存页,从而进行通信。
  • 具体实现
    1. 首先,内核会为全局所有的共享内存维护一个全局的队列结构
    2. 队列的每一项(shmid_kernel结构体)是和一个IPC key 绑定的
    3. 各进程可以通过同样一个key,来找到并使用同一段共享物理内存区域。
5. 信号进程间通信
  1. 信号的特点是单向的时间通知能力。
  • 相比而言,信号量也有通知能力,但是需要进程主动去查询计数器状态或陷入堵塞状态(来等待通知)
  • 而信号机制接收事件的进程不需要堵塞等待该进程,内核会帮助其切换到对应的处理函数中响应信号事件
信号的基本概念
  • 信号传递的信息很短,只有一个编号(信号编号)
  • 一个进程会为一些特定的信号编号注册处理函数,当进程接收到对应的信号时,内核会自动的将该用户的控制流切换到对应的处理函数中。
6. 套接字进程间通信
  1. 套接字是一种既可用于本地,又可跨网络使用的通信机制。

7.3 微内核进程间通信

  • 在微内核架构下,原本的系统调用需要通过进程间通信的方式实现。
  • 原来的一次系统调用变成了 两次系统调用 + 中间通信处理逻辑的开销
  • 剩下的太多了,不太理解,二刷之后整理
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值