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