今天我们来分享一下,Linux中关于进程通行中最简单的匿名管道的实现和相关性质的验证。
进程通信的原理是:多个进程看到同一份公共资源(文件),能对该资源进行相应操作,不同进程间即可进行通信。一般有操作系统(内核)提供这一公共资源。今天我们利用匿名管道来实现进程通信。
首先介绍一下,匿名管道的特点:
1.匿名管道只能实现单向通信。
2.匿名管道只能实现有血缘关系的进程之间的通信。
3.管道是一个随进程的文件,即当进程退出时,管道文件不存在。
4.管道的数据通信是基于数或者字节流的通信。
5.管道内部实现同步互斥,满足安全性,保证数据的一致性。
接着,举例父子进程的通信来说明匿名管道的通信过程。
A.利用pipe函数建立匿名管道,得到管道的读写文件描述符。
B.fork创建子进程。由于管道的读写文件描述符属于数据,子进程会依照父进程复制一份,即父子同时拥有指向管道文件的读写文件描述符,用有一份公共的管道文件,就拥有了进程通行的条件。
C.由于匿名管道只能实现进程间的单项通信,所以需要手动关闭父子进程冗余的读写端(读写文件描述符)。
注:子写父读,关闭子进程的读端和父进程的写端。需求不同则反之。
D.父子进程进行相应的读写,实现进程通信。
图解如下:
我们需要验证以下四种情况:
A.读端不关闭,且不读取管道内容,写端不断向管道写内容,当管道被写满,写端只能阻塞式等待。
部分代码截图和运行结果如下:
B.写端不关闭,且不向管道写内容,读端不断读取管道内容,当管道中数据读完,读端只能阻塞式等待。
部分代码截图和运行结果如下:
C.读端先于写端关闭,写端收到异常信号退出。
部分代码截图和运行结果如下:
D.写端先于读端关闭,当读到0时,即读到文件结尾,退出。
部分代码截图和运行结果如下:
实现进程通信——匿名管道,代码如下:
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
int main()
{
umask(0);
int pfd[2];
if(pipe(pfd) < 0){
perror("pipe wrong!\n");
exit(1);
}
pid_t id = fork();
if(id<0){
perror("wrong!\n");
exit(1);
}
if(id == 0){//child
close(pfd[0]);
int i = 0;
char* tmp = "hello !";
// while(1){
// i++;
// if(i < 5){
// printf("child: %s, num: %d\n", tmp, i);
// write(pfd[1], tmp, strlen(tmp));
// }
// else//i>=5
// {
// exit(1);
// }
// sleep(1);
// }
// exit(1);
while(1){
printf("child: %s, num: %d \n", tmp, i);
i++;
if(i>10)return 0;
write(pfd[1], tmp, strlen(tmp));
}
}
else{//parent
int status;
close(pfd[1]);
char tmp[1024];
int i=0;
while(1){
ssize_t s = read(pfd[0], tmp, sizeof(tmp)-1);
// if(i>5) close(pfd[0]);
// i++;
if(s>0){
tmp[s] = 0;
printf("parent:%s\n", tmp);
}
else if(s == 0){//child quit,so parent will quit
printf("child quit,so parent will quit!\n");
sleep(5);
break;
}
// else{//wrong
// printf("read wrong!\n");
// int status;
// pid_t s = waitpid(id, &status, 0);
// if(s>0){
// printf("waitpid success! sig:%d, exitCode: %d\n",\
// WIFEXITED(status),WEXITSTATUS(status) );
// }
// exit(2);
// }
}
if(waitpid(id, &status, 0)>0){
printf("waitpid success! sig:%d, exitCode: %d\n",\
WIFEXITED(status),WEXITSTATUS(status) );
}
}
return 0;
}
分享如上,欢迎斧正!
注:代码虽乱但全。若有错误和遗漏,请参见代码截图或评论!