进程间通信

一,为什么操作系统给用户提供进程间通信的方式

  • 因为进程之间有独立的地址空间,导致进程间无法直接进行通信
  • 场景:数据传输,数据共享,进程控制,事件通知

二, 分类

  • 管道(命名管道和匿名管道)—(传输数据)
  • 消息队列—(传输数据)
  • 信号量—(进程间的访问控制)
  • 共享内存—(数据共享)
管道—进程间数据资源的传输
1,特点
  • 半双工通信----(双向选择的单向通信)数据只能从这一端流向对端–可供用户选择的单向通信
  • 提供流式服务,面向字节流的数据传输—传输灵活但是会造成数据粘连
  • 管道的生命周期随进程,
读写特性
  • 如果管道中无数据,read会阻塞,直到读到数据然后返回(管道的大小是有限制的,一般为64k)
  • 如果管道中数据满了,write会阻塞,直到数据被读取,管道中有空闲位置,然后写入数据后返回,
  • 如果管道的所有读端都被关闭,则write会触发异常–SIGPIPE—使进程退出
  • 如果管道的所有写端都关闭,则read读完数据后返回0,通知用户没人写数据了
  • 自带同步与互斥特性 当读写大小小于PIPE_BUF(4096)时保证操作的原子性—操作不可被打断
    • 互斥—保证对临界资源(都可以访问到的公共资源)同一时间的唯一访问性
    • 同步—保证对临界资源访问的时序可控性—保证公平,我操作的时候你不能操作(互斥),我操作的完了你才能操作(同步)
2,原理
  • 内核的一块缓冲区,通信双方都可以访问到的区域
    在这里插入图片描述
  • 管道本质就是一个内核的缓冲区,因此在使用管道通信的过程中,涉及到用户态和内核态数据交换的问题,因此比较慢,两次拷贝(第一次用户态数据拷贝到内核态的缓冲区,第二次是将内核态数据拷贝到用户态)
3,匿名管道(pipe)
  • 只能用于具有亲缘关系的进程间通信----父进程创建一个匿名管道,然后fork创建子进程,子进程复制了父进程的文件描述符表,因此子进程也有两个文件描述符指向该缓冲区。因此父子进程都用文件描述符标识一个管道,可以实现进程间通信
  • 接口int pipe(int pipefd[2])— pipefd是输出型参数,返回两个文件描述符,pipefd[0]读数据 另一个写数据,返回值-1表示失败,
  • ps -ef | grep ssh
4,命名管道(fifo)
  • 可见于文件系统,因为创建命名管道会随之在文件系统中创建一个命名管道文件,因为所有的进程都可以通过打开管道文件,进而获得命名管道的操作句柄,因此命名管道可以用于同一主机上任意进程间通信,
  • 管道的原理依然是内核的缓冲区,只是通过文件向所有进程都提供了能够访问管道的方法,
  • 匿名管道和命名管道的区别------通信范围的大小不同
命名管道的的打开特性,
  • 若管道没有被写的方式打开,这时候如果只读打开就会阻塞,直到文件以被写的方式打开
  • 若管道没有被读的方式打开,这时候如果只写打开就会阻塞,直到文件以被读的方式打开
  • 若管道以读写方式打开,则不会阻塞
  • 其他读写特性与匿名管道一致
  • 管道文件ls -al 是以p开头的
匿名管道和命名管道的区别
  • 匿名管道只能用于具有亲缘关系的进程间通信(匿名管道没有名字,只能通过fork的操作让子进程获得和父进程相同的文件描述符),而命名管道可以让同一主机上的任意两个进程实现通信,(命名管道有名字,可见于文件系统)
共享内存—(内存共享数据共享)
原理
  • 多个进程将同一块物理空间映射到自己的虚拟地址空间中,达到数据共享的目的,这是最快的IPC方式,
  • 在物理内存上开辟一块空间,将这块空间映射到进程的虚拟地址空间上,进程可以通过虚拟地址进行访问操作,如果一块内存被多个进程映射,那么多个进程访问同一块内存可以实现进程间通信
    在这里插入图片描述
  • 相较于其他IPC方式(将数据从用户态拷贝到内核态,用的时候从内核态拷贝到用户态),共享内存少了两次拷贝操作,共享内存可以直接通过(虚拟)地址间接堆内存操作,并且反馈到其他进程,
使用流程
  • 创建共享内存 shmget
  • 将共享内存映射到虚拟地址空间 shmat
  • 对共享内存进行操作 memcpy…
  • 解除映射关系 shmdt
  • 删除共享内存 shmctl
接口
  • 创建共享内存-----int shmget(key_t key, size_t size, int shmflg);
    1,key:共享内存标识 操作系统中的标识符(共享内存的名字)----key_t ftok(const char *pathname, int proj_id) 通过文件的iNode节点和proj_id共同得出一个key的值,
    2,size:共享内存大小
    3,shmflg:打开方式/创建权限—IPC_CREAT 共享内存不存在就创建,存在就打开 —IPC_EXCL 与ICP_CREAT同用,若存在就报错,不存在就创建 —mode_flags 权限
    4, 返回值:操作句柄shmid(程序内部的标识符,通过这个id来操作共享内、存),失败返回-1;
  • 将共享内存映射到虚拟地址空上—void *shmat(int shmid, const void *shmaddr, int shmflg);
    1,shmid 创建共享内存返回的操作句柄
    2, shmaddr ,用于指定映射在虚拟地址空间的首地址,通常为NULL
    3,shmflg 通常为0—可读可写
    4,返回值:成功—返回映射首地址(通过这个地址对共享内存操作) 失败—(viod星号)-1
  • 解除映射关系 —int shmdt(const void *shmaddr)
    1,传输虚拟地址空间的首地址,也就是shmat的返回值
  • 删除共享内存----int shmctl(int shmid, int cmd, struct shmid_ds *buf)
    1,shmid ---- 贡献内存的操作句柄
    2, cmd ----- 对共享内存要进行的操作(删除)
    IPC_RMID 删除共享内存(删除共享内存,并不是立即删除的,因为这个共享内存可能还连接的有其他进程,只是拒绝后续映射连接,当贡献内存的映射连接数为0的时候则删除内存(nattch(映射连接数)))
    3, buf ---- 设置或者获取一些信息放到buf中,用不上就置为NULL
共享内存查看
  • ipcs 查看进程间通信的方式
  • ipcs -m 查看共享内存
  • ipcrm -m shmid 删除指定的共享内存
消息队列
原理
  • 消息队列传输的是有类型的数据块,用户可以根据自己的需要选择性的获取某些类型的数据,
  • 在操作系统内核维护了一个环形链式队列,具有head和tail,有数据来了往里面插入一个数据块,这个数据块大致是一个结构体,是一个具有类型的数据块
  • 当有进程获取数据的时候,从head开始遍历,找到对应类型的数据并返回
  • 消息队列提供了一个进程向另一个进程发送一块数据的方法,每个数据块都被认为是有一个类型的,接收进程的数据块可以有不同的类型值
流程
  • 创建---------添加数据节点------------获取数据节点---------------删除
  • msgget------msgsnd----------------- msgrc------------------msgctl
现状
  • 消息队列现状几乎已经被淘汰了,主要因为限制太多了,比如底层维护的结构体中的msg_qbytes表示传输的最大字节数,意思是传输的大小有上限,
信号量
  • 相当于内核中具有等待队列的计数器,用于资源计数,没资源就等待,有资源就唤醒
  • 若计数<=0表示没有资源可用,没有资源字需要等待,如计数>=0表示有资源可用,则可以获取资源,然后计数减一,
  • 如何等待:如果某一个进程释放了资源,并且有进程在等待,则计数加一,并且唤醒等待的进程
  • 信号量实现进程间的同步与互斥(二元信号量,信号量的值只存在1和0),

三,几种进程间通信方式的对比

匿名管道和命名管道优缺点
优点:
  • 如果传输的数据大小在规定范围内,4k以内就会自带同步与互斥,很安全
  • 命名管道可以实现同一台主机的任意两个进程之间的通信问题
缺点:
  • 底层的缓冲区太小,导致传输的数据大小有上限
  • 匿名管道只用于有亲缘关系的进程间通信,有局限
  • 管道是半双工的通信的,数据只能流向一个方向,如果要实现双向通信,要创建两个管道,很繁琐
  • 管道传输以流的方式传输,导致数据粘连,数据本身没有边界
消息队列
优点:
  • 自带同步与互斥机制,底层缓冲区或者单消息的大小只要不超过64k就不会就很安全
  • 可以提供双向通信,要加一个标识
  • 可以通过消息中的type进行分类,将type值设置为进程的pid,就可以实现父进程处理父进程接收的任务,子进程处理子进程的任务
缺点:
  • 缓冲区还是太小了,存在上限,
  • 只能用于同一个key值的进程间通信,只要有相同的key值,进程就可以定位到同一个消息队列上
共享内存
优点:
  • 几乎没有上限
  • 没有单向通信的限制
  • 不局限于父子进程间的通信
缺点:
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值