3.1 进程间通信之管道
Posted 程序猿爱吃鸡
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了3.1 进程间通信之管道相关的知识,希望对你有一定的参考价值。
一、引言
管道作用于有血缘关系的进程间的通信,完成数据传递。实际为内核使用环形队列机制,借助内核缓冲区(4k)实现。有如下特质:
1) 其本质是一个伪文件(实为内核缓冲区)
2) 由两个文件描述符引用,一个表示读端,一个表示写端。可定义一个文件描述符数组,存取。
3) 规定数据从管道的写端流入管道,从读端流出。
4) 数据自己读不能自己写,数据一旦被读走,便不在管道中存在,不可反复读取。 由于管道采用半双工通信方式。因此,数据也只能在一个方向上流动。
5) 只能在有公共祖先的(血缘关系的)进程间使用管道。
二、pipe函数
调用pipe系统函数即可创建一个管道,其函数原型为:
int pipe(int fd[2]);
成功:0;失败:-1,设置errno
向管道文件读写数据其实是在读写内核缓冲区,函数参数数组包含pipe使用的两个文件的描述符:fd[0] → r; fd[1] → w,就像0对应标准输入,1对应标准输出一样。注意:在pipe使用时,无需open,但需手动close。
管道方法通信流程:
1) 父进程调用pipe函数创建管道,得到两个文件描述符fd[0]、fd[1]指向管道的读端和写端。
2) 父进程调用fork创建子进程,那么子进程也有两个文件描述符指向同一管道。
3) 父进程关闭管道读端,子进程关闭管道写端。父进程可以向管道中写入数据,子进程将管道中的数据读出。由于管道是利用环形队列实现的,数据从写端流入管道,从读端流出,这样就实现了进程间通信。
三、例程
1 #include <unistd.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <stdio.h> 5 #include <sys/wait.h> 6 7 int main(void) 8 { 9 pid_t pid; 10 char buf1[1024]; 11 int fd[2]; 12 int len; 13 char *buf2 = "hello world\\n"; 14 15 if (pipe(fd) == -1) //创建管道 16 printf("pipe error\\n"); 17 18 pid = fork(); //创建进程 19 if (pid < 0) { 20 printf("fork error\\n"); 21 } 22 else if (pid == 0) { 23 close(fd[1]); //子进程关闭写端 24 len = read(fd[0], buf1, sizeof(buf));//读取管道数据到buf中 25 write(STDOUT_FILENO, buf1, len);//将buf数据写入标准输出 26 close(fd[0]); //注意要close 27 } 28 else { 29 close(fd[0]);//父进程关闭读端 30 write(fd[1], buf2, strlen(buf2));//向管带的写端写入字符串p 31 wait(NULL); //等待子进程释放 32 close(fd[1]); 33 } 34 35 return 0; 36 }
编译执行结果:
补充:
读管道:
1)管道中有数据,read返回实际读到的字节数。
2)管道中无数据:
(1) 管道写端被全部关闭,read返回0 (好像读到文件结尾)
(2) 写端没有全部被关闭,read阻塞等待(不久的将来可能有数据递达,此时会让出cpu)
写管道:
1)管道读端全部被关闭, 进程异常终止(也可使用捕捉SIGPIPE信号,使进程不终止)
2)管道读端没有全部关闭:
(1) 管道已满,write阻塞。
(2) 管道未满,write将数据写入,并返回实际写入的字节数。
缓冲大小:使用ulimit –a 命令来查看当前系统中创建管道文件所对应的内核缓冲区大小
以上是关于3.1 进程间通信之管道的主要内容,如果未能解决你的问题,请参考以下文章