IPC:进程间通信,通过内核提供的缓冲区进行数据交换的机制。
方式:
- pipe 管道—最简单
- fifo 有名管道
- mmap 文件映射共享IO—速度最快
- 本地socket 最稳定
- 信号—携带信息量最小
- 共享内存—用特定API申请的一块内存,进程退出,其他进程仍可访问这块内存
- 消息队列
1 使用pipe进行父子进程间通信
1 |
|
常见通信方式:单工(广播);半双工(同一个时刻,数据只能往一个方向发,对讲机);全双工(打电话)。
管道:半双工
父子进程通信:
1 |
|
管道实例:ps aux|grep bash
1 |
|
读管道:
若写端全部关闭—read读到0,相当于读到文件末尾
若写端没有全部关闭
有数据—read读到数据
没有数据–read阻塞,fcntl函数可以更改非阻塞
写管道:
若读端全部关闭—会产生一个13号信号SIGPIPE,程序异常终止;
若读端未全部关闭
管道已满—write阻塞
管道未满—write正常写入
计算管道大小:
ulimit -a
查看上限512*8
long fpathconf(int fd,int name);
管道优劣:
- 优点:简单,相比信号,套接字实现进程间通信,简单很多。
- 缺点:1. 只能单向通信,双向通信需建立两个管道。
2. 只能用于父子、兄弟进程(有共同祖先)间通信。该问题后来使用fifo有名管道解决。
2 使用pipe进行兄弟进程间通信
1 |
|
3 使用fifo进行无血缘关系的进程间通信
FIFO 有名管道,实现无血缘关系间的管道通信
通过队列实现,内核会针对fifo文件开辟一个缓冲区,操作fifo文件,可以操作缓冲区,实现进程间通信–实际上就是文件读写。
1 | $ mkfifo myfifo 命令创建 |
fifo读
1 |
|
fifo写
1 |
|
open注意:打开fifo文件的时候,read端会阻塞等待write端open,同理,write端也会阻塞等待read端open。
4 mmap函数的使用
把文件中的一段内容映射到内存中的映射区,操作内存
1 |
|
创建映射区
void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
○ addr 传NULL
○ length 映射区的长度
○ prot
- PROT_READ 可读
- PROT_WRITE 可写
○ flags
- MAP_SHARED 共享的,对内存的修改会影响到源文件
- MAP_PRIVATE 私有的
○ fd 文件描述符,open打开一个文件
○ offset 偏移量
- 成功 返回 可用的内存首地址
- 失败 返回 MAP_FAILED
释放映射区
int munmap(void *addr, size_t length);
○ addr 传mmap的返回值
○ length mmap创建的长度
- int munmap(void *addr, size_t length);
- mmap共享映射区
○ 返回值
1 |
|
mmap九问:
如果更改mem变量的地址,释放的时候munmap,传入mem还能成功吗?不能!!
如果对mem越界操作会怎么样?文件的大小对映射区操作有影响,尽量避免。
如果文件偏移量随便填个数会怎么样?offset必须是 4k的整数倍
如果文件描述符先关闭,对mmap映射有没有影响?没有影响
open的时候,可以新创建一个文件来创建映射区吗?不可以用大小为0的文件
open文件选择O_WRONLY,可以吗? 不可以: Permission denied
当选择MAP_SHARED的时候,open文件选择O_RDONLY,prot可以选择 PROT_READ|PROT_WRITE吗?Permission denied ,SHARED的时候,映射区的权限<= open文件的权限
mmap什么情况下会报错?很多情况
如果不判断返回值会怎么样? 会死的很难堪!!
5 mmap函数创建匿名映射区的方法
父子进程通信(利用匿名映射区):
1 |
|
6 mmap函数进行有血缘关系的进程间通信
父子进程通信(利用文件):缺点:用了一个文件,并没用到文件内容
1 |
|
7 mmap函数进行无血缘关系的进程间通信
1 |
|