操作系统—进程间通信(IPC)
概述
-
进程通信的机制及同步
-
不使用共享变量的进程通信
-
I P C f a c i l i t y IPC\ facility IPC facility 提供 2 2 2 个操作:
➢ s e n d ( m e s s a g e ) send (message) send(message) - 消息大小固定或者可变
➢ r e c e i v e ( m e s s a g e ) receive (message) receive(message)
-
如果 P P P 和 Q Q Q 想通信,需要:
➢ 在它们之间建立通信链路
➢ 通过 s e n d / r e c e v i e send/recevie send/recevie 交换消息
-
通信链路的实现
➢ 物理(例如,共享内存,硬件总线)
➢ 逻辑(例如,逻辑属性)
通信模型
直接及间接通信
直接通信
-
进程必须正确的命名对方:
➢ s e n d ( P , m e s s a g e ) send(P,\ message) send(P, message)- 发送消息到进程 P P P
➢ r e c e i v e ( Q , m e s s a g e ) receive(Q,\ message) receive(Q, message) - 从进程 Q Q Q 接收信息
-
通信链路的属性
➢ 自动建立链路
➢ 一条链路恰好对应一对通信进程
➢ 每对进程之间只有一个链路存在
➢ 链路可以是单向的,但通常是双向的
间接通信
-
定向从消息队列接收消息
➢ 每个消息队列都有一个唯一的 I D ID ID
➢ 只有它们共享了一个消息队列,进程才能够通信
-
通信链路的属性
➢ 只有进程共享一个共同的消息队列,才建立链路
➢ 链接可以与许多进程相关联
➢ 每对进程可以共享多个通信链路
➢ 链接可以是单向或者双向
-
操作
➢ 创建一个新的消息队列
➢ 通过消息队列发送和接收消息
➢ 销毁消息队列
-
原语的定义如下:
➢ s e n d ( A , m e s s a g e ) send(A,\ message) send(A, message) - 发送消息到队列 A A A
➢ r e c e i v e ( A , m e s s a g e ) receive(A,\ message) receive(A, message) - 从队列 A A A 接受消息
阻塞和非阻塞区
通信链路缓冲
队列的消息被附加到链路,可以是以下3种方式之一:
-
0 0 0 容量 - 0 m e s s a g e 0\ message 0 message
发送方必须等待接收方(rendezvous)
-
有限容量 - n m e s s a g e s n\ messages n messages 的有限长度
发送方必须等待,如果队列满
-
无限容量 - 无限长
发送方不需要等待
信号
-
Signal(信号)
➢ 软件中断通知事件处理
➢ Examples:SIGFPE,SIGKILL,SIGUSRI,SIGSTOP,SIGCONT
-
接收到信号时会发生什么?
➢ 捕获(Catch):指定信号处理函数被调用
➢ 忽略(Ignore):依靠操作系统的默认操作
√ Example:Abort,memory dump,suspend or resume process
➢ 屏蔽(Mask):禁止进程接受和处理信号,闭塞信号因此不会传送
√ 可能是暂时的(当处理同样类型的信号)
-
不足
➢ 传送的信息量小,只有一个信号类型,不能传输要交换的任何数据
信号使用示例
管道
管道(Pipe),用于数据交换
-
子进程从父进程继承文件描述符
➢ file descriptor: 0 stdin,1 stdout,2 stderr
-
进程不知道(或不关心!)另一端,从键盘,文件,程序读取 或 写入到终端,文件,程序。
与管道相关的系统调用
-
读管道:
read(fd, buffer, nbytes)
➢
scanf()
是基于它实现的 -
写管道:
write(fd, buffer, nbytes)
➢
printf()
是基于它实现的 -
创建管道:
pipe(rgfd)
➢
rgfd
是2个文件描述符组成的数组➢
rgfd[0]
是读文件描述符➢
rgfd[1]
是写文件描述符
管道示例
% ls | more
Shell创建管道,创建两个进程子进程ls、more, 管道相当于是内存的一块buffer,对于ls来说是stdout,管道写端,对于more来说是stdin,管道读端。
因为ls和more有一个共同的父进程Shell,所以这两个子进程可以继承父进程的一些资源,管道是一种以文件形式存在的。
消息队列
-
消息队列按FIFO来管理消息
➢ Message:作为一个字节序列存储
➢ Message Queues:消息数组
➢ FIFO & FILO configuration
消息队列的系统调用
-
msgget(key, flags)
➢ 获取消息队列标识
-
msgsnd(QID, buf, size, flags)
➢ 发送消息
-
msgrcv(QID, buf, size, type, flags)
➢ 接收消息
-
msgctl(…)
➢ 消息队列控制
共享内存
管道和消息队列可以理解为间接通信方式,共享内存是一种直接通信方式。
共享内存是把同一个物理内存区域同时映射到多个进程的内存地址空间的通信机制,在最开始的时候就创建好了一块或者多块共享区域,使多个进程可以共享。
-
进程
➢ 每个进程都有私有地址空间
➢ 在每个地址空间内,明确地设置了共享内存段
-
优点
➢ 快速,方便地共享数据
-
不足
➢ 必须同步数据访问,使用额外的同步机制来协调
共享内存的实现
-
最快的方法
-
一个进程写另一个进程立即可见
-
没有系统调用干预
-
没有数据复制
-
不提供同步
➢ 由程序员提供同步
共享内存系统调用
-
shmget(key, size, flags)
➢ 创建共享段
-
shmat(shmid, *shmaddr, flags)
➢ 把共享段映射到进程地址空间
-
shmdt(*shmaddr)
➢ 取消共享段到进程地址空间的映射
-
shmctl(…)
➢ 共享段控制
-
需要信号量等机制协调共享内存的访问冲突
还有一种更广泛的通信:Socket
机制。
整理自 【清华大学】 操作系统