Linux进程间通信

1. 概述

  • 进程通信的方式
    • 管道
      有名管道 fifo
      无名(匿名)管道 pipe
    • 内存映射区
    • 信号 -----> 不推荐使用的
      在linux中信号的优先级非常高, 会打乱程序的正常执行顺序
    • 本地套接字
    • 共享内存 shm -> share memory
    • 消息队列
    • 文件 -----> 一般不用

2.管道

  • 管道的本质:

    就是一块内存(在内核中),默认大小4k
    通过队列(环形队列)的方式在进行数据维护
    数据只能读一次,管道默认阻塞
    管道两端各自提供一个文件描述符,进行管道读写

    • 管道读写
    	// 读管道
    	ssize_t read(int fd, void *buf, size_t count);
    	// 写管道
    	ssize_t write(int fd, const void *buf, size_t count);
    

2.1 匿名管道

  • 匿名管道特点:

    在磁盘没有实体,对应内核某块内存
    默认是阻塞的
    管道是单工的,数据从写端流向读端
    有血缘关系的进程间通信

  • 创建匿名管道

     #include <unistd.h>
    
    // 参数是一个传出参数, 数组有两个值, 
    // pipefd[0] -> 管道的读端, pipefd[1] -> 管道的写端
    int pipe(int pipefd[2]);
    返回值:
    	成功: 0, 失败: -1
    
  • 管道的读写行为

    • 读管道
      • 写端没关闭
        • 有数据: 读数据, read()返回读到的字节数
        • 没有数据: read()阻塞, 等待写端写数据, 如果有数据之后, 解除阻塞继续读, 读完继续阻塞
      • 写端关闭了
        • 如果管道中还有数据, read()将数据都读出, 再次读管道里边没有数据, read() 返回0
    • 写管道
      • 读端没有关闭
        • 写满了: 写端阻塞, 当管道数据被读端读走之后, 继续写, 写满之后继续阻塞
        • 没有满: 不阻塞, 一直写数据, 写满之后就阻塞了
      • 读端关闭了
        • 管道破裂了, 当前进程会被一个信号杀死 SISPIPE

2.2 有名管道

  • 有名管道特点

    有名管道是一个内核的缓冲区(内核中的一块内存) -> 存储数据的位置
    有名管道在磁盘上是有实体的 -> 是一个管道文件, 大小永远是0
    数据只能读一次,有名管道到fifo
    可以实现没有血缘关系的进程间通信,默认阻塞

  • 创建方式

    # 使用函数
    #include <sys/stat.h>
    int mkfifo(const char *pathname, mode_t mode);
    参数:
    - pathname: 有名管道文件在磁盘上的位置和名字
    - mode: 用户多管道的操作权限, 最终权限: (mode & ~umask)
    返回值:
    	成功: 0, 失败: -1
    # 第二种创建方式, 使用shell命令
    $ mkfifo  NAME...
    

3. 内存映射

有一个磁盘文件, 某个进程通过调用一个函数 mmap可以在当前进程的虚拟地址空间中申请一块内存, 将磁盘文件中的内容映射到这块内存中. 这块内存就叫内存映射区
两个进程通过内存映射区实现进程间通信, 每个进程中都有一块属于自己的内存映射区

  • 内存映射区作用:

    • 进程间通信(实现没有血缘关系的进程间通信) -> 一般不用
    • 使用mmap读写文件, 提供IO效率
      • 使用内存映射区实现文件拷贝
  • 内存映射区, 需要一个块内存, 哪儿的内存?

    • 内存是进程的虚拟地址空间中的 -> 动态库加载区那一块
      在这里插入图片描述
  • 创建内存映射区

    #include <sys/mman.h>
    // 创建内存映射区
    void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
    参数:
    	- addr: 要创建的内存映射区的起始地址, NULL-> 委托内核指定
        - length: 要创建的内存映射区大小, 假设写100, 实际得到的是4k
            - 这个长度实际是4k的整数倍
            - 这个长度必须要大于0
            - 如果参数指定为100, 实际得到内存映射区4k, 剩余3996会被填充为0, 这部分数据是可以合理访问的
        - prot: 对内存映射区数据的操作权限
            - PROT_EXEC: 对映射区数据有执行权限
            - PROT_READ: .............读权限, 常用
            - PROT_WRITE: ............写权限, 常用
            - PROT_NONE: .............没有任何权限
        - flags: 映射区的属性
            - MAP_SHARED: 共享映射区, 如果是想进程间通信必须要指定这个值
            - MAP_PRIVATE: 映射区是私有的, 不能实现进程间通信
        - fd: 通过打开一个磁盘文件, 得到了这个文件描述符, 这个磁盘文件数据被映射到内存映射区
        - offset: 进行映射的时候, 文件的偏移量, 这个值必须是4k的整数倍, 不偏移指定为0
            
    返回值:
    	成功: 得到创建的内存映射区的起始地址
        失败: MAP_FAILED [(void*)-1]
    
  • 释放内存映射区

    // 释放内存映射区
    int munmap(void *addr, size_t length);
    参数:
    	- addr: 要是释放的内存映射区的起始地址, mmap的返回值
        - length: 创建的内存映射区的大小, 和mmap的第二个参数值相等即可
    返回值: 
    	成功: 0, 失败: -1
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值