文章目录
1. 进程间通信方式分类
一共七类
早期的进程间通信方式:
- 无名管道、有名管道、信号通信
SYSEM V: (IPC对象)
- 消息队列、共享内存、信号灯集
BSD:
- 套接字通信
共享内存是所有进程间通信方式中效率最高的,因为它直接操作物理内存
信号通信是进程间通信方式中唯一的异步通信机制
无名管道、有名管道、信号通信、消息队列、共享内存、信号灯集,这6种通信方式只能实现一台主机的多个进程间通信
套接字可以实现不同主机间多个进程的通信
2. 进程间通信实现方式
任何一个进程在开启或者创建之后,系统都会分配4G虚拟空间,包含1G内核空间和3G用户空间,用户空间是当前进程私有的,而内核空间是一个操作系统中所有进程所公有的,所以进程间通信机制的本质就是在内核空间开辟区域,多个进程同时对同一个开辟的区域操作,从而实现进程间的通信
所以这七种进程间通信方式基本都是在学习如何在内核空间开辟区域,然后如何操作的问题
3. 无名管道
3.1 概念
无名管道就是在内核空间开辟一块区域,然后会给进程两个文件描述符,只要多个进程可以得到这两个文件描述符,就可以对同一个管道进行操作
无名管道是一个半双工的通信方式,意味着有固定的读端和写端
无名管道只能用于具有亲缘关系的进程间通信,原因是因为无名管道既然给当前进程的是两个文件描述符,那么这两个文件描述符的创建只能在当前进程的用户空间,当fork之后产生的进程,会继承原本父进程的所有的空间,所以他能得到这两个文件描述符及对应的文件表项(struct file
)
3.2 相关函数
#include <unistd.h>
int pipe(int pipefd[2]);
功能:
创建一个无名管道
参数:
pipefd:保存两个文件描述符的数组
pipefd[0] 用于读操作
pipefd[1] 用于写操作
返回值:
成功:0
失败:-1
//注意:管道无法使用lseek改变文件的偏移量
// if(lseek(pipefd[0], 10, SEEK_SET) == -1)
// {
// perror("lseek error");
// exit(1);
// }
读写规律
读写段 | 读操作 | 写操作 | 现象 |
---|---|---|---|
读写段都存在 | 只读 | - | 管道中有数据,则正常读取;无数据会阻塞 |
读写段存在 | - | 只写 | 一直向管道中写数据,直到管道满(默认无名管道为64kBytes) |
关闭写段,只有读端 | 只读 | - | 如果管道中有数据,则正常读取;如果管道中没有数据,读操作返回0 |
关闭读段,只有写端 | - | 只写 | 当执行第一个写操作时,当前系统中会产生一个信号SIGPIPE,这个信号的名字称之为管道破裂,这个信号默认对当前进程的处理是结束进程 |
3.3 无名管道实现进程间通信
由于无名管道是通过调用函数直接给当前进程两个文件描述符,所以没关系的进程无法获得相同的两个文件描述符,所以只有使用fork之后创建的进程才可以继承这两个文件描述符,所以无名管道只能使用在具有亲缘关系的进程间通信
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char const *argv[])
{
int pipefd[2];
if(pipe(pipefd) == -1)
{
perror("pipe error");
exit(1);
}
pid_t pid;
if((pid = fork()) == -