开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 20 天,点击查看活动详情。
一、进程间通信的常用方式,特征
-
管道:简单
-
信号:开销小
-
mmap映射:非血缘关系进程间
-
socket(本地套接字):稳定
二、管道
-
实现原理: 内核借助环形队列机制,使用内核缓冲区实现。
-
特质:
-
伪文件
-
管道中的数据只能一次读取。
-
数据在管道中,只能单向流动。
-
-
局限性:
-
自己写,不能自己读。
-
数据不可以反复读。
-
半双工通信。
-
血缘关系进程间可用。
-
管道原理图
三、pipe函数 创建,并打开管道。
int pipe(int fd[2]);
-
参数:
fd[0]: 读端。
fd[1]: 写端。
-
返回值:
成功: 0
失败: -1 errno
四、管道的读写行为
- 读管道:
-
管道有数据,
read返回实际读到的字节数。 -
管道无数据:
1)无写端,read返回0 (类似读到文件尾)
2)有写端,read阻塞等待。
- 写管道:
-
无读端, 异常终止。 (SIGPIPE导致的)
-
有读端:
1) 管道已满, 阻塞等待
2) 管道未满, 返回写出的字节个数。
管道通信
示例程序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
void sys_err(const char *str)
{
perror(str);
exit(1);
}
int main(int argc, char *argv[])
{
int ret;
int fd[2];
pid_t pid;
char *str = "hello pipe\n";
char buf[1024];
ret = pipe(fd);
if (ret == -1)
sys_err("pipe error");
pid = fork();
if (pid > 0) {
close(fd[0]); // 关闭读段
sleep(3);
//write(fd[1], str, strlen(str));
close(fd[1]);
} else if (pid == 0) {
close(fd[1]); // 子进程关闭写段
ret = read(fd[0], buf, sizeof(buf));
printf("child read ret = %d\n", ret);
write(STDOUT_FILENO, buf, ret);
close(fd[0]);
}
return 0;
}
五、管道分类
-
pipe管道: 用于有血缘关系的进程间通信。 ps aux | grep ls | wc -l
父子进程间通信:
兄弟进程间通信:
-
fifo管道:可以用于无血缘关系的进程间通信。
命名管道: mkfifo
无血缘关系进程间通信:
-
读端,open fifo O_RDONLY
-
写端,open fifo O_WRONLY
-