Почему дочерний процесс ожидает при использовании fork и pipe для stdin из родительского вывода? - PullRequest
0 голосов
/ 12 декабря 2018

Я понял, как работают fork и pipe, но у меня есть сомнения относительно потока дочернего и родительского процесса. Так как мы используем 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; 
}

1 Ответ

0 голосов
/ 12 декабря 2018

Вы не закрываете достаточно файловых дескрипторов в дочернем элементе.

Правило большого пальца : Если вы dup2() один конец канала для стандартного вводаили при стандартном выводе закройте оба исходных дескриптора файла, возвращенных pipe(), как можно скорее.В частности, вы должны закрыть их перед использованием любого из семейства функций exec*().

Правило также применяется, если вы дублируете дескрипторы с dup() или fcntl() с F_DUPFD

В этом случае ребенок должен закрыть fds[1] после его дублирования.Поскольку он все еще открыт, rev никогда не получит EOF, потому что существует процесс (rev дочерний процесс), который теоретически может записывать данные на вход.

Вместо этого следует использовать fclose(stream)close(fds[1]), потому что вывод буферизован и fclose() знает, что нужно очистить буферы, но close() не имеет понятия.Однако, используя fflush(stream) перед ошибочным close(), вы избегаете проблем.

Это приводит к:

#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;
}

, который производит вывод:

From there to here,
and here to there,
funny things are everywhere.
 - Dr. Seuss
...