Linux:进程间通信(IPC)

进程间通信


1、进程间通信的概念

进程间通信是操作系统为用户提供的几种通信方式。

进程间因为每一个进程都有一个虚拟地址空间,在保证了进程独立性的同时,却使得进程间无法直接通信,因此需要操作系统来提供进程间通信方式,并且因为通信的场景不同,所以提供的方式也有多种。

2、进程间通信的目的
  • 数据传输:一个进程需要将它的数据发送给另一个进程
  • 资源共享:多个进程之间共享同样的资源。
  • 通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止
    时要通知父进程)。
  • 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另
    一个进程的所有陷入和异常,并能够及时知道它的状态改变
3、进程间通信方式的种类

(System V标准)

  • 管道:用于进程间的数据传输
  • 共享内存:用于进程间的数据共享
  • 消息队列:用于进程间的数据传输
  • 信号量:用于进程间的数据控制
  • Socket通信(后面介绍)
3.1 管道
管道的本质

内核中的一块缓冲区—通过半双工通信实现数据
通过让多个进程都能访问到同一块缓冲区来实现进程通信

  • 单工:已经确定方向,只能进行单向通信
  • 双工:具有双向性,可以互相进行通信
  • 半双工:原本具有双向性,但是只能选择方向进行单向通信
管道的分类
  • 匿名管道
  • 命名管道

匿名管道

这块内核中的缓冲区没有标识,其他进程无法直接访问管道
只能用于具有亲缘关系的进程间通信(只能使用父子进程复制的方式获取操作句柄)

创建管道时,操作系统会提供两个操作句柄(文件描述符),其中一个用于管道读取数据,另一个向管道写入数据,因此只能通过创建子进程,子进程通过复制父进程的方式,获取到管道的操作句柄进而实现访问同一个管道通信。

创建匿名管道

//常见一个匿名管道,向用户通过参数pipefd返回管道的操作句柄
int pipe(int pipefd[2])
//pipefd[0]:用于从管道读取数据
//pipefd[1]:用于向管道写入数据
//返回值:成功返回0,失败返回-1

特性

  • 若管道中没有数据,则read会阻塞;
  • 若管道写满了,继续write则会阻塞;
  • 管道自带同步与互斥
  • 若管道中所有的写端都被关闭(表示当前没有进程写入数据),read读完管道中的数据之后,就不会再阻塞,而是返回0
  • 若管道中所有的读端都被关闭(表示没有进程读取数据了),继续write会触发异常,程序退出

同步:通过条件判断,判断当前进程是否能访问,不能访问则等待,能访问的时候再唤醒,实现临界资源(临界资源表示大家都能访问到的资源)访问的合理性
体现:若管道中没有数据,则read会阻塞;若管道写满了,继续write则会阻塞。

互斥:通过保证同一时间只有一个进程能够访问临界资源,保证临界资源的安全性。
体现:安全性是指对管道进行数据操作的大小不超过 PIPE_BUF=4096(默认大小) 的时候,则保证操作的原子性。( 原子性是指一步完成,不可被打断)

同步保证访问临界资源的合理性,但是不保证安全性;
互斥保证访问临界资源的安全性,但是不保证合理性。

关闭读端/写端

//关闭写端
close(pipefd[1]);

//关闭读端
close(pipefd[0]);

ps -ef 命令的默认功能:将结果写入到标准输出
grep ssh 一直从标准输入读取数据进行过滤(如果读不到数据则等待)

命名管道

内核中的缓冲区具有标识符(标识符是一个可见于文件系统的管道文件),其他进程可以通过这个标识符找到这个缓冲区(通过打开一个管道文件,进而访问同一块缓冲区),进而实现通信

创建命名管道

//命令
mkfifo filenam

//接口
int mkfifo(const char *pathname, mode_t mode);
//pathname:管道文件名称
//mode:文件权限
//成功返回0,失败返回-1

打开特性

  • 若管道文件以只读的方式打开,则会阻塞,直到这个管道文件被以写的方式打开
  • 若管道文件以只写的方式打开,则会阻塞,直到这个管道文件被以读的方式打开
  • 若管道文件以读写的方式打开,则不会阻塞

管道特性

  • 管道生命周期随进程
  • 半双工通信
  • 自带同步与互斥
  • 提供字节流服务—有序、连接、可靠的字节流传输–传输比较灵活
3.2 共享内存

最快的进程间通信方式
实现原理

  • 在物理内存上开辟一块内存空间
  • 将这块物理内存映射到进程的虚拟地址空间
  • 进程就可以通过虚拟地址直接访问这块物理内存

多个进程要映射同一块物理内存,就可以通过这块内存实现数据共享
在这里插入图片描述
共享内存是最快的进程间通信方式的原因
因为共享内存直接通过虚拟空间地址映射访问物理内存,而其他方式都是内核中的缓冲区,在通信时都会涉及用户态与内核态之间的两次数据拷贝,通信速度会减慢;
共享内存少了两次用户态与内核态的数据拷贝,因此通信速度更快。

共享内存的操作流程

  1. 创建共享内存(开辟物理内存空间,具有标识符)

  2. 将共享内存映射到各个进程的虚拟地址空间

  3. 直接通过虚拟地址进行内存操作

  4. 解除映射关系

  5. 删除共享内存

  6. 创建共享内存

int shmget(key_t key,int size,int flag)
//key:共享内存的标识符,多个进程通过相同的标识符可以打开同一块共享内存
//size:共享内存的大小
//flag:IPC_CREAT | IPC_EXCL | 权限
//返回值:成功返回一个操作句柄,失败返回-1
  1. 将共享内存段连接到进程地址空间
void *shmat(int shmid,void *addr,int flag);
//shmid:共享内存的操作句柄
//addr:映射到虚拟地址空间的首地址,通常置空NULL,一般由操作系统来决定
//flag:通常置0(可读可写)==> 前提是拥有设置可读可写的权限  SHM_RDONLY 只读
//返回值:成功返回映射到虚拟地址空间的首地址,通常这个地址对内存进行操作,失败返回-1 
  1. 解除映射
int shmdt(void *shmstart);
//shmstart:映射到虚拟地址空间的首地址
//返回值:成功返回0,失败返回-1
  1. 删除映射
int shmctl(int shmid, int cmd,struct shmid_ds *buf);
//shmid:操作句柄
//cmd:具体对共享内存要进行的操作----IPC_RMID--删除共享内存
//返回值:成功返回0,失败返回-1

相关命令:
ipcs 查看进程间通信资源
ipcrm 删除进程间通信资源
ipcs -m 查看共享内存
ipcs -q 查看消息队列
ipcs -s 查看信号量

ipcrm -m shmid 删除进程间通信资源
当删除共享内存的时候,共享内存不会立即被删除(因为有可能会造成正在访问的进程崩溃),而是将key修改为0,表示这块共享内存将不再继续接收映射链接,当这块共享内存的映射链接数为0 的时候,则自动释放

特性

  • 最快的进程间通信方式
  • 生命周期随内核

共享内存的操作是不安全的(并不会自动具备同步于互斥关系,需要操作用户进行控制)

3.3 消息队列

本质上就是内核中的一个优先级队列,多个进程通过向同一个队列添加节点和获取节点实现通信,传输一个有类型(优先级)的数据块

特性

  • 自带同步与互斥
  • 生命周期随内核
  • 数据传输自带优先级

注意事项:
struct msgbuf{int type,char buf[***]};这个结构体需要用户自定义

msgget 创建
msgsnd 添加节点
msgrcv 获取节点
msgctl 操作–删除消息队列 IPC_RMID

3.4 信号量

用于实现进程间的同步与互斥
信号量本质:内核中的一个计数器+pcb等待队列(对资源进行计数)

  • 同步:通过条件判断,判断当前进程是否能访问,不能访问则等待,能访问的时候再唤醒,实现临界资源访问的合理性
    同步的实现: 信号量是一个对资源的计数,可以通过计数判断是否能够获取一个资源进行处理,若计数<0,则表示不能获取(并且对计数-1),需要等待(加入pcb队列),此时若其他进程生产一个资源,则会对计数+1,若计数<=0,则唤醒一个进程。(只保证合理,不保证安全)

  • 互斥:通过保证同一时间只有一个进程能够访问临界资源,保证临界资源的安全性。
    互斥的实现:通过只有0或1 的计数器,实现临界资源访问状态的标记;在访问临界资源之前先获取信号量,计数-1;若计数<0,则使进程等待(将进程pcb加入队列中);否则可以对临界资源进行访问(并且在访问期间,已经将临界资源的状态置位不可访问状态,因此可以保证其他进程不会再访问临界资源),当前进程访问完毕后,则对计数进行+1,则唤醒一个进程(将一个pcb出队,置位运行状态)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值