IO-потоки в процессе fork () - PullRequest
2 голосов
/ 29 июля 2011

Выполнен следующий пример кода, но вывод из разветвленного процесса не читается: на консоли ничего не отображается, пока я не нажму enter, а затем «Сбой чтения!» показывает.

Вопрос в том, почему так, и как я могу взаимодействовать с stdin и stdout из fork() 'ed процесса?

/* example1.c */

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>

int main() {
    pid_t pid = fork();

    if (!pid) {
        // child

        char s[64];
        printf("Enter something: ");
        char *res = fgets(s, 64, stdin);
        if (!res) {
            printf("Read failed!\n");
        } else {
            printf("You entered: %s", s);
        }
    }

    return 0;
}

Обновление:

Еще один пример странного поведения потоков ввода-вывода:

/* example2.c */

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>

int main() {
    pid_t pid = fork();

    if (!pid) {
        // child

        char *argv[] = {
            "-c",
            "/home/user/echo.sh",
            NULL
        };

        execv("/bin/sh", argv);
    }
    return 0;
}

echo.sh скрипт:

#!/bin/sh

read -p "Enter something: " INPUT
echo "You entered $INPUT"

Этот возвращает

Enter something: /home/user/echo.sh: line 3: read: read error: 0: Input/output error
You entered

Обновление 2:

Похоже, этот код делает именно то, что нужно:

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>

int main() {
    pid_t pid = vfork();
    if (!pid) {
        // child
        system("/home/user/echo.sh");
    }
    return 0;
}

Решением было заменить fork на vfork. Я просто не знаю, почему этот работает ...

Ответы [ 3 ]

2 голосов
/ 29 июля 2011

Я думаю, что вы хотите wait(2). Как в

/* example1.c */

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>

int main() {
    int status;
    pid_t pid = fork();

    if (!pid) {
        // child

        char s[64];
        printf("Enter something: ");
        char *res = fgets(s, 64, stdin);
        if (!res) {
            printf("Read failed!\n");
        } else {
            printf("You entered: %s", s);
        }
    }
    else
    {
        while (wait(&status) != pid);
    }
    return 0;
}
1 голос
/ 29 июля 2011

Это связано с тем, что ваш дочерний процесс сейчас находится в потерянной группе процессов, где ни один процесс не является прямым потомком оболочки (который должен выполнять управление заданиями).

Потерянная группа процессов: Группа процессов, у которой по крайней мере нет члена, у которого есть родительский элемент не в группе процессов, а в том же сеансе (~ является прямым потомком оболочки).

Пока родительский и дочерний элементы работают, ситуация выглядит следующим образом:

$ ps fax -o pid,pgid,sid,ppid,tty,stat,time,cmd
27177 27177 27177 32170 pts/6    Ss   00:00:00  |   \_ /bin/bash
 4706  4706 27177 27177 pts/6    S+   00:00:00  |       \_ ./ex1
 4707  4706 27177  4706 pts/6    S+   00:00:00  |           \_ ./ex1

В группе процессов 4706 есть два процесса, 4706 и 4707. 4706 - это дочерний элемент 27177, который находится втот же сеанс (27177), но другая группа процессов (27177): это оболочка, которая имеет дело с управлением заданиями для группы процессов 4706.

Когда родитель умирает, ситуация выглядит следующим образом:

$ ps fax -o pid,pgid,sid,ppid,tty,stat,time,cmd
27177 27177 27177 32170 pts/6    Ss+  00:00:00  |   \_ /bin/bash
 4664  4663 27177     1 pts/6    S    00:00:00 ./ex1

В группе 4663 только один процесс, 4664, и его родитель (init) не находится в одном сеансе.Оболочка не может иметь дело с управлением заданиями для этой группы процессов, поэтому read() и write() get EIO.

0 голосов
/ 29 июля 2011

Если вы работаете в UNIX / Linux, когда stdout входит в консоль, он буферизуется.То есть вы не увидите никаких выходных данных, пока не выполните одно из следующих действий:

  • fflush(stdout)
  • prinf("\n")
  • переполнения буфера stdout.

Когда стандартный вывод идет куда-то еще (например, канал файла), он полностью буферизуется, то есть printf("\n") не очищает буфер.

...