Linux下的进程间通信(IPC)

进程间通信(IPC)

为什么要进程通信?

为什么要进程间通信:大项目的模块化,协同运行

  1. 数据传输

    一个进程需要将它的数据发送到另一个进程

  2. 资源共享

    多个进程之间共享同样的资源

  3. 通知事件

    一个进程要向另一个程序发送通知消息,通知它们发生了某种事件,比如子进程终止时要通知父进程

  4. 进程控制

    有些进程希望完全控制另一个进程的执行(比如 : DEGUG),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够知道他们状态的改变。

为什么进程通信需要操作系统提供接口:因为独立性

  • 操作系统如何能够让进程之进行通信:给多个进程之间提供一个公共的,都能访问到的媒介
  • 操作系统因为提供进程间通信的使用场景不同,因此提供的进程间通信方式也有多种,各自也有各自的特点,本质上都是提供多个进程都能访问的缓冲区
进程间通讯的发展
  1. 管道
    • 匿名
    • 命名
  2. SystemV 标准 (系统调用使用)
    • ​消息队列(数据传输)
    • ​共享内存(资源共享)
    • 信号量(事件通知)
  3. POSIX 标准 (标准c库使用)
    • 消息队列
    • 共享内存
    • 互斥量
    • 条件变量
    • 信号量
    • 读写锁
管道
  • 用于在进程间传输数据资源
  • 对于管道这块缓冲区的操作,和io操作使用同一套接口
  • 管道的特性
    • 管道时半双工通讯(单向通讯)
    • 读写特性
      • 如果管道中没有数据,则read会阻塞,直到读取出数据
      • 如果管道中数据满了,则write会阻塞,直到有数据被读出去
      • 如果管道的所有写端都被关闭,那么读端读完管道中的数据之后,返回0
      • 如果管道的所有读端都被关闭,那么写端写入数据的时候会触发异常,退出进程
    • 管道自带同步与互斥保护操作
      • 当对管道的读写数据大小不大于PIPE_BUF时候,将保证数据读写的原子性
    • 提供字节流服务(数据传输灵活,但是有可能造成数据的粘连)
    • 生命周期随进程
    • 匿名管道:只能用于具有亲缘关系的进程
  • 匿名管道
    • 创建的缓冲区没有标识,因此只能用于具有亲缘关系的进程间通信,创建一个管道,返回两个文件描述符,这时创建一个子进程,子进程复制父进程,因此子进程也有相同的描述符指向内核相同的缓冲区,这是就可以通信了

      int pipe (int fds[2]);

在这里插入图片描述

  • 一个例子

    利用管道函数pipe实现进程间通讯

  • 命名管道

    可见于文件系统,所以所有的进程可以通过打开文件,获取到内核管道这块缓冲区对应的描述符.因此命名管道可以用于同一机器上的任一进程间通讯

    • 创建命名管道

    mkfifo test.fifo

    • int mkfifo(const char *parhname, mode_t mode)
      • 8功能:创建一个管道文件
      • 参数:
        • pathname : 路径
        • mode : 权限
      • 返回值:成功0 失败 -1
    • 命名管道的特性
      • 命名管道与匿名管道各种特性都一样(除了亲缘间进程通信)
      • 命名管道的打开特性
        • 如果管道文件只读打开,将阻塞,直到有这个文件被以写的方式打开
        • 如果管道文件只写打开,将阻塞,直到有这个文件被以读的方式打开
        • 如果管道文件以读写打开,则就不阻塞
  • 同步:对临界资源操作的时序可控性
  • 互斥:对临界资源在同一时间的唯一访问性
消息队列

内核创建一个队列,实现进程间的数据传输

传输的是有类型的数据块,类型(整数)可以用于定义优先级,用于区分进程,用于区分数据功能

限制:最大的占用字节数大小限制

  1. 获取/创建消息队列
    #include <sys/msg.h>	
    #include <sys/ipc.h>
    int msgget(
        key_t key ,  // 相当于文件名
        int flags	// 创建  IPC_CREAT | 0644(权限) 
    				// 打开  0
    );
    
    返回值:消息队列的id ,相当于文件描述符
  • 查看IPC对象
    • ipcs -q //查看消息队列 查看IPC对象
    • ipcrm -Q key //删除指定key的消息队列 删除IPC对象
    • 系统中最多可以创建多少个消息队列?​
      • cat /proc/sys/kernel/msgmni //最多创建个数
      • cat /proc/sys/kernel/msgmax //一条消息最多装多少字节
      • cat /proc/sys/kernel/msgmnb //一个消息队列中一个消息的总字节数是多少
  1. 发送消息
    int msgsnd(int msgid, //msgget的返回值
        const void* msgp, //消息的位置必须是类似于
                          //msgbuf的结构体
        size_t len , //消息的长度不包括type的大小
        int flag    //消息的标志位
    );
    
    返回值 :失败 -1 成功 0
    struct msgbuff{
    	long type ; 		//消息类型	必须 >= 1	必须有
    	//随便				//随意类型,写上自己的消息
    }	
    
  2. 接收消息
    ssize_t msgrcv(
        int msgid, //msgget的返回值
        void *msgp, //取出消息存放位置
        size_t msgsz, //装消息位置的大小,不包括类型
        long msgtype, //取那个类型的消息
        int msgflag //选项,一般填0,表示没有消息就在等,有了就取出来
    );
    
  • 返回值:失败:-1 成功 :实际拷贝的字节数
共享内存
  • 特点
    • 进程间通讯最快的方式

在这里插入图片描述

  1. 创建或者打开共享内存

    shmget(
        key_t key, //共享内存的标识符(可以使用ftok创建)
        size_t size, //共享内存的大小
        int flag  //创建IPC_CREAT|0664	打开0
    );
    
    • 若描述符key存在,则后两个参数无效
    • 返回值:失败 -1 成功 返回操作句柄
  2. 让共享内存与本进程建立关系(将共享内存映射到进程中)

    void  *shmat(
        key_t key, 
        const char* shmaddr, //让操作系统挂载到地址空间的 位置若为NULL,这让操作系统自己选择 
        int flag  // 0
    );
    
    • 返回值:成功返回 实际挂载到虚拟地址空间的起始位置 失败返回 (void *) -1;
  3. 卸载掉共享内存(解除映射关系)
    int shmdt(void * shmaddr);

  4. 删除共享内存

    int shmctl(
        key_t key, 
        int cmd, //IPC_RMID 删除共享内存
        NULL //本来这里是个结构体,但是删除用不上,直接填NULL
    )
    
  • 删除共享内存,并不会直接删除,先是等待 nattch(将该共享内存映射到自己地址空间的进程个数) 变成 0,并在等待期间,拒绝新的映射链接
信号量
  • 是什么?

    其实就是一个计数器 + 等待队列 --> 用于对资源进行计数

    • 获取一个资源,计数 - 1,如果没有资源,计数为零,为了获取资源因此死等
    • 回收一个资源,计数 + 1,唤醒死等,唤醒的是信号量等待队列上的进程
  • 功能就是等待与唤醒:用于实现进程间的同步与互斥

    • 同步:对资源操作时,如果计数为0,标示没有资源,代表不能操作则死等,资源回收后计数 + 1,被唤醒才能进行操作
    • 互斥:计数只有0和1,要不然有资源操作,要不然没有资源操作
      • 别人拿走资源,计数变成0,不能操作则死等,意味着别人对资源操作期间谁都无法堆资源进行操作

由于本人才疏学浅,若有疏漏还望不吝赐教。
@YeLing0119

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值