进程间通信-管道 IPC pipe
@(Linux)
参考
http://akaedu.github.io/book/ch30s04.html#id2868153
问题1
在例 30.7 “管道”中,父进程只用到写端,因而把读端关闭,子进程只用到读端,因而把写端关闭,然后互相通信,不使用的读端或写端必须关闭,请读者想一想如果不关闭会有什么问题。
如果不关闭,后面写的会把前面写的覆盖。
而且由于不能控制多进程的流程,有可能自己读了自己的内容,没读到对方传来的内容。
问题2
请读者修改例 30.7 “管道”的代码和实验条件,验证我上面所说的四种特殊情况。
情况1
所有指向管道写端的文件描述符都关闭了(管道写端的引用计数等于0),而仍然有进程从管道的读端读数据,那么管道中剩余的数据都被读取后,再次read会返回0,就像读到文件末尾一样。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define MAXLINE 80
int main()
{
int n;
int fd[2];
pid_t pid;
char linep[MAXLINE];
char linec[MAXLINE];
if (pipe(fd) < 0)
{
perror("pipe");
exit(1);
}
if ((pid = fork()) < 0)
{
perror("fork");
exit(1);
}
if (pid > 0)// parent, write
{
close(fd[0]);
//sleep(1);
write(fd[1], "hello child", 11);
close(fd[1]);
//read(fd[0], linep, MAXLINE);
//printf("now the parent read: %s\n", linep);
wait(NULL);
}
else// child, read
{
close(fd[1]);
//write(fd[1], "hi parent", 9);
int res0 = read(fd[0], linec, MAXLINE);
printf("res0 = %d, now the child read: %s\n", res0, linec);
int res1 = read(fd[0], linec, MAXLINE);
printf("res1 = %d, now the child read: %s\n", res1, linec);
//sleep(1);
}
return 0;
}
情况2
如果有指向管道写端的文件描述符没关闭(管道写端的引用计数大于0),而持有管道写端的进程也没有向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余的数据都被读取后,再次read会阻塞,直到管道中有数据可读了才读取数据并返回。
int main()
{
int n;
int fd[2];
pid_t pid;
char linep[MAXLINE];
char linec[MAXLINE];
if (pipe(fd) < 0)
{
perror("pipe");
exit(1);
}
if ((pid = fork()) < 0)
{
perror("fork");
exit(1);
}
if (pid > 0)// parent, write
{
close(fd[0]);
sleep(10);
write(fd[1], "hello child", 11);
close(fd[1]);
//read(fd[0], linep, MAXLINE);
//printf("now the parent read: %s\n", linep);
wait(NULL);
}
else// child, read
{
close(fd[1]);
//write(fd[1], "hi parent", 9);
printf("child blocked, waiting..\n");
int res0 = read(fd[0], linec, MAXLINE);
printf("res0 = %d, now the child read: %s\n", res0, linec);
//int res1 = read(fd[0], linec, MAXLINE);
//printf("res1 = %d, now the child read: %s\n", res1, linec);
//sleep(1);
}
return 0;
}
情况3
如果所有指向管道读端的文件描述符都关闭了(管道读端的引用计数等于0),这时有进程向管道的写端write,那么该进程会收到信号SIGPIPE,通常会导致进程异常终止。在第 33 章 信号会讲到怎样使SIGPIPE信号不终止进程。
int main()
{
int n;
int fd[2];
pid_t pid;
char linep[MAXLINE];
char linec[MAXLINE];
if (pipe(fd) < 0)
{
perror("pipe");
exit(1);
}
if ((pid = fork()) < 0)
{
perror("fork");
exit(1);
}
if (pid > 0)// parent, write
{
close(fd[0]);
sleep(1);
int res = write(fd[1], "hello child", 11);
printf("write res: %d\n", res);
close(fd[1]);
//read(fd[0], linep, MAXLINE);
//printf("now the parent read: %s\n", linep);
wait(NULL);
}
else// child, read
{
close(fd[1]);
close(fd[0]);
//write(fd[1], "hi parent", 9);
//printf("child blocked, waiting..\n");
//int res0 = read(fd[0], linec, MAXLINE);
//printf("res0 = %d, now the child read: %s\n", res0, linec);
//int res1 = read(fd[0], linec, MAXLINE);
//printf("res1 = %d, now the child read: %s\n", res1, linec);
//sleep(1);
}
return 0;
}
情况4
如果有指向管道读端的文件描述符没关闭(管道读端的引用计数大于0),而持有管道读端的进程也没有从管道中读数据,这时有进程向管道写端写数据,那么在管道被写满时再次write会阻塞,直到管道中有空位置了才写入数据并返回。
int main()
{
int n;
int fd[2];
pid_t pid;
char linep[MAXLINE];
char linec[MAXLINE];
if (pipe(fd) < 0)
{
perror("pipe");
exit(1);
}
if ((pid = fork()) < 0)
{
perror("fork");
exit(1);
}
if (pid > 0)// parent, write
{
close(fd[0]);
for (int i = 0; ; i++)
{
int res = write(fd[1], "hello child 11111111", 20);
printf("%d th write res: %d\n",i, res);
}
close(fd[1]);
//read(fd[0], linep, MAXLINE);
//printf("now the parent read: %s\n", linep);
wait(NULL);
}
else// child, read
{
close(fd[1]);
printf("child blocked, waiting..\n");
sleep(5);
while (1)
{
int res0 = read(fd[0], linec, MAXLINE);
printf("# read res0 = %d, now the child read: %s\n", res0, linec);
sleep(1);
}
}
return 0;
}