C 为什么子进程在使用来自父级的stdin的fork和pipes时正在等待';谁的产量?

C 为什么子进程在使用来自父级的stdin的fork和pipes时正在等待';谁的产量?,c,pipe,fork,low-level,C,Pipe,Fork,Low Level,我了解fork和管道是如何工作的,但我对子进程和父进程的流程有疑问。因为我们使用fork,父进程和子进程的执行顺序没有定义,但为什么子进程等待父进程的stdin。如果子进程先执行,会发生什么?它必须在控制台中打印为空?但它没有发生我能知道为什么吗 #include <stdio.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> int main () { i

我了解fork和管道是如何工作的,但我对子进程和父进程的流程有疑问。因为我们使用fork,父进程和子进程的执行顺序没有定义,但为什么子进程等待父进程的stdin。如果子进程先执行,会发生什么?它必须在控制台中打印为空?但它没有发生我能知道为什么吗

#include <stdio.h> 
#include <sys/types.h> 
#include <sys/wait.h> 
#include <unistd.h>
int main () {
int fds[2]; pid_t pid;
/* File descriptors for the two ends of the pipe are placed in fds. */
pipe (fds);
/* Fork a child process. */ 
pid = fork ();
if (pid == (pid_t) 0) {
/* Child proces -. Close the write end of the file descriptor. */
close (fds[1]);
/* Connect the read end of the pipe to standard input. */
dup2 (fds[0], STDIN_FILENO);
/* Replace the child process with the “rev” program. */
execlp("rev", "rev", 0); }

else {
/* This is the parent process. */
    FILE* stream;
/* Close the read end of the file descriptor. */
    close (fds[0]);
/* Convert the write file descriptor to a FILE object */
    stream = fdopen (fds[1], "w");
    fprintf (stream, ",ereh ot ereht morF\n");
    fprintf (stream, ",ereht ot ereh dna\n");
    fprintf (stream, ".erehwyreve era sgniht ynnuf\n"); 
    fprintf (stream, "ssueS .rD - \n");
    fflush (stream);
    close (fds[1]);
/* Wait for the child process to finish. */
    waitpid (pid, NULL, 0);
}
    return 0; 
}
#包括
#包括
#包括
#包括
int main(){
int fds[2];pid_t pid;
/*管道两端的文件描述符放置在fds中*/
管道(fds);
/*派生子进程。*/
pid=fork();
如果(pid==(pid_t)0){
/*子进程-。关闭文件描述符的写入端*/
关闭(fds[1]);
/*将管道的读取端连接到标准输入*/
dup2(fds[0],标准文件号);
/*用“rev”程序替换子进程*/
execlp(“rev”,“rev”,0);}
否则{
/*这是父进程*/
文件*流;
/*关闭文件描述符的读取端*/
关闭(fds[0]);
/*将写入文件描述符转换为文件对象*/
流=fdopen(fds[1],“w”);
fprintf(流,“,ereh-ot-ereht-morF\n”);
fprintf(流,“,ereht或ereh dna”);
fprintf(流,“.erehwyreve era sgniht ynnuf”);
fprintf(流,“问题研究-\n”);
流;
关闭(fds[1]);
/*等待子进程完成*/
waitpid(pid,NULL,0);
}
返回0;
}

您没有关闭子文件中足够的文件描述符

经验法则:如果 将管道的一端连接到标准输入或标准输出,关闭两个 返回的原始文件描述符 尽快。 特别是,在使用任何 函数族

如果将描述符与 或 使用
F_DUPFD

在这种情况下,子项需要在复制后关闭
fds[1]
。因为它仍然打开,
rev
将永远不会收到EOF,因为理论上有一个进程(子进程)可以写入输入

您应该使用
fclose(stream)
而不是
close(fds[1])
,因为输出是缓冲的,
fclose()
知道刷新缓冲区,但是
close()
没有任何线索。但是,通过在错误的
close()
之前使用
fflush(stream)
,可以避免出现问题

这导致:

#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>

int main(void)
{
    int fds[2];
    pid_t pid;

    pipe(fds);

    pid = fork();
    if (pid == (pid_t)0)
    {
        close(fds[1]);
        dup2(fds[0], STDIN_FILENO);
        close(fds[1]);
        execlp("rev", "rev", 0);
    }
    else
    {
        FILE *stream;
        close(fds[0]);
        stream = fdopen(fds[1], "w");
        fprintf(stream, ",ereh ot ereht morF\n");
        fprintf(stream, ",ereht ot ereh dna\n");
        fprintf(stream, ".erehwyreve era sgniht ynnuf\n");
        fprintf(stream, "ssueS .rD - \n");
        fclose(stream);
        waitpid(pid, NULL, 0);
    }
    return 0;
}

您没有在子项中关闭足够的文件描述符

经验法则:如果 将管道的一端连接到标准输入或标准输出,关闭两个 返回的原始文件描述符 尽快。 特别是,在使用任何 函数族

如果将描述符与 或 使用
F_DUPFD

在这种情况下,子项需要在复制后关闭
fds[1]
。因为它仍然打开,
rev
将永远不会收到EOF,因为理论上有一个进程(子进程)可以写入输入

您应该使用
fclose(stream)
而不是
close(fds[1])
,因为输出是缓冲的,
fclose()
知道刷新缓冲区,但是
close()
没有任何线索。但是,通过在错误的
close()
之前使用
fflush(stream)
,可以避免出现问题

这导致:

#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>

int main(void)
{
    int fds[2];
    pid_t pid;

    pipe(fds);

    pid = fork();
    if (pid == (pid_t)0)
    {
        close(fds[1]);
        dup2(fds[0], STDIN_FILENO);
        close(fds[1]);
        execlp("rev", "rev", 0);
    }
    else
    {
        FILE *stream;
        close(fds[0]);
        stream = fdopen(fds[1], "w");
        fprintf(stream, ",ereh ot ereht morF\n");
        fprintf(stream, ",ereht ot ereh dna\n");
        fprintf(stream, ".erehwyreve era sgniht ynnuf\n");
        fprintf(stream, "ssueS .rD - \n");
        fclose(stream);
        waitpid(pid, NULL, 0);
    }
    return 0;
}

child和parent将并行执行,因此child将在读取时阻塞,直到稍晚一点,此时parent有机会执行一段时间并将一些数据放入管道中……为了便于可读性和理解:1)一致地缩进代码。在每个左大括号“{”之后缩进。在每个右大括号“}”之前取消缩进。建议每个缩进级别为4个空格。2) 遵循公理:每行一条语句,每条语句(最多)一个变量声明。函数:
fork()
有三种返回1)0表示父进程正在执行。代码需要检查所有三种类型的返回值:
execlp(“rev”,“rev”,0);}如果此语句返回,则表示发生错误。因此,语句后面应该跟着:
perror(“execlp失败”);退出(退出失败)关于:
管道(fds)始终检查返回值以确保操作成功。子级和父级将并行执行,因此子级将在读取时阻塞,直到稍晚一点,此时父级有机会执行一段时间并将一些数据放入管道中…以便于可读性和理解:1)一致地缩进代码。在每个左大括号“{”之后缩进。在每个右大括号“}”之前取消缩进。建议每个缩进级别为4个空格。2) 遵循公理:每行一条语句,每条语句(最多)一个变量声明。函数:
fork()
有三种返回1)0表示父进程正在执行。代码需要检查所有三种类型的返回值:
execlp(“rev”,“rev”,0);}如果此语句返回,则表示发生错误。因此,语句后面应该跟着:
perror(“execlp失败”);退出(退出失败)关于:
管道(fds)始终检查返回值以确保操作成功。