三十一. 复习文件描述符重定向
在下面的图中,dup2(fd[1],1)这里的1号文件描述符,跟随老的fd[1],由于这里1号文件描述符,已经有指向,于是原指向关系撤销,1重新建立指向,并指向fd[1]所在。
接下来,grep "bash"这里是从0号文件描述符,即STDIN_FILENO中读取内容,本来STDIN_FILENO指向的是/dev/tty,也就是终端,换言之。如果没有管道和重定向的话,grep "bash"将直接从终端中读取内容
然而现在,我们通过dup2(fd[0],0)这一操作,使得0号文件描述符,重新定向到了内核缓冲区的读端,因此,现在的grep"bash"指读取的内容,实际是0号文件描述符现在所指的内核缓冲区中的读端。
三十二. 复习有血缘关系的进程间通信思路
下图所示,是子进程写,父进程读。。。
如果说父进程读,子进程写,那么我们需要再创建另一个管道,并且对于父进程,关闭写端。对于子进程,关闭读端。
三十三. 兄弟进程间通信
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <sys/wait.h>
int main(int argc, const char* argv[])
{
int fd[2];
int ret = pipe(fd);
if(ret == -1)
{
perror("pipe error");
exit(1);
}
printf("fd[0] = %d\n", fd[0]);
printf("fd[1] = %d\n", fd[1]);
int i = 0;
int num = 2;
for(; i<num; ++i)
{
pid_t pid = fork();
if(pid == 0)
{
break;
}
}
// parent recyle child pcb
if(i == num)
{
close(fd[0]);
close(fd[1]);
// recyle
pid_t wpid;
while( (wpid = waitpid(-1, NULL, WNOHANG)) != -1 )
{
if(wpid == 0)
{
continue;
}
printf("died child pid = %d\n", wpid);
}
}
else if(i == 0)
{
// ps aux
close(fd[0]);
dup2(fd[1], STDOUT_FILENO);
execlp("ps", "ps", "aux", NULL);
}
else if(i == 1)
{
// grep bash
close(fd[1]);
dup2(fd[0], STDIN_FILENO);
execlp("grep", "grep", "bash", NULL);
}
printf("pipe[0]="%d\n",fd[0]);
printf("pipe[1]="%d\n",fd[1]);
return 0;
}
三十四. 创建子进程需要判断pid是否为0
三十五. 管道的读写行为