进程间通信
IPC: Inter Processes Communication
- 进程是一个独立的资源分配单位,不同进程(用户进程)的资源是独立的,没有关联,不能在一个进程中直接访问另一个进程的资源。
- 但是进程不是孤立的,不同的进程需要进行信息的交互和状态的传递等,因此需要进程间通信
进程间通信的目的
- 数据传输:一个进程需要将他的数据发送给另一个进程
- 通知事件:一个进程需要向另一个或一组进程发送消息,通知他们发生了某种事件(如进程终止时要通知父进程)
- 资源共享:多个进程之间共享同样的资源。为了做到这一点,需要内核提供互斥和同步机制。
- 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程)此时控制进程徐望能够拦截另一个进程的所有陷入和异常,并能够及时知道他的状态改变。
进程间通信方式
1. 匿名管道(问题:管道特点)
管道也叫无名(匿名)管道
统计文件数目ls | wc -l
- 管道其实是一个在内核内存中维护的缓冲器,这个缓冲器的存储能力是有限的,不同的操作系统大小不一
- 管道拥有文件的特质:读写,匿名管道无文件实体,有名管道有文件实体,但不存储数据。可以按照操作文件的方式操作管道
- 一个管道是一个字节流,使用管道时不存在消息或者消息边界的概念,从管道读取数据的进程可以读取任意大小的数据,而不管写入进程写入管道的数据块的大小是多少
- 通过管道的数据是有顺序的,先写入的先读出,读出的顺序和他们被写入管道的顺序是一样的
- 管道是单向的,半双工的
- 从管道读数据是一次性操作,数据一旦被读走,他就从管道中被抛弃,释放空间以便写入更多的数据,在管道中无法使用lseek()来随机的访问数据
- 管道只能在具有公共祖先的进程之间使用
设置管道非阻塞
int flag = fcntl(pipefd[0], F_GETFL); // 获取原来的flag
flag |= O_NONBLOCK; // 修改flag的值
int ret = fcntl(pipefd[0], F_SETFL); // 设置新的flag
2. 有名管道(FIFO)
匿名管道没有名字,只能用在亲缘关系的进程间通信,为了克服这个缺点,提出了有名管道(FIFO)
- 有名管道提供了一个路径名与之关联,以FIFP文件形式存在文件系统中,只要访问该路径就能够彼此通过FIFO相互通信,因此通过FIFO不想管的进程也能交换数据。
1.FIFO的内容在内存中
2. 当使用FIFO的进城退出后,FIFO讲继续保存在文件系统中以便以后使用
3. FIFO有名字
创建有名管道
int ret = access("fifo1", F_OK);
if(ret == -1) {
printf("管道不存在,创建管道\n");
ret = mkfifo("fifo1", 0664);
if(ret == -1) {
perror("mkfifo");
exit(0);
}
}
有名管道的注意事项:
1. 一个为只读而打开一个管道的进程会阻塞,直到另外一个进程为只写打开管道
2. 一个为只写而打开一个管道的进程会阻塞,直到另外一个进程为只读打开管道
-
读管道:
- 管道中有数据,read返回实际读到的字节数
- 管道中无数据:
- 管道写端被全部关闭,read返回0,(相当于读到文件末尾)
- 写端没有全部被关闭,read阻塞等待
-
写管道:
- 管道读端被全部关闭,进行异常终止(收到一个SIGPIPE信号)
- 管道读端没有全部关闭:
- 管道已经满了,write会阻塞
- 管道没有满,write将数据写入,并返回实际写入的字节数。