Ну, во-первых, ваш родительский процесс ожидает завершения дочернего процесса в системном вызове wait(2)
, в то время как ваш дочерний процесс заблокирован в канале read(2)
для другого символа. Оба процесса заблокированы ... поэтому вам нужно действовать извне, чтобы снять их. Проблема в том, что дочерний процесс не закрывает свой дескриптор записи канала (а также родительский дескриптор не закрывает свой дескриптор чтения канала, но здесь это не влияет). Просто канал блокирует любого читателя, хотя бы один такой дескриптор записи все еще открыт. Только когда все дескрипторы записи закрыты, чтение возвращает читателю 0
.
Когда вы сделали fork(2)
, оба дескриптора канала (fd[0]
и fd[1]
) были dup()
изменены на дочерний процесс, поэтому у вас есть канал с двумя открытыми файловыми дескрипторами (один в родительском, один в дочернем) для записи и два открытых дескриптора (опять же, один в родительском, один в дочернем) для чтения, так как один Writer остается с открытым каналом для записи (в данном случае дочерний процесс), чтение, сделанное дочерним процессом, все еще блокируется. Ядро не может обнаружить это как аномалию, потому что ребенок все еще может писать в конвейер, если другой поток (или обработчик сигнала) захочет.
Кстати, я собираюсь прокомментировать некоторые вещи, которые вы сделано неправильно в вашем коде:
- во-первых, вы рассматриваете только два случая из
fork()
для родителя и для дочернего элемента, но если вилка завершится неудачно, она вернет -1
, а вы у вас будет родительский процесс, записывающий в канал без процесса чтения, поэтому, вероятно, он должен заблокироваться (как я уже сказал, это не ваш случай, но это тоже ошибка). Вы всегда должны проверять наличие ошибок из системных вызовов и не думайте, что ваш вызов fork()
никогда не завершится ошибкой (подумайте, что -1
считается != 0
и поэтому он не проходит через родительский код). Есть только один системный вызов, который вы можете выполнить, не проверяя его на наличие ошибок, и это close(2)
(хотя по этому поводу много разногласий) - То же самое происходит с
read()
и write()
. Лучшим решением вашей проблемы было бы использование большего буфера (а не только одного символа, чтобы уменьшить количество системных вызовов, выполняемых вашей программой и, таким образом, ускорить ее) и использовать возвращаемое значение read()
в качестве параметра в вызов write()
.
Ваша программа должна (действительно, в моей системе) работать, просто вставив следующую строку:
close(fd[1]);
непосредственно перед while
l oop в дочернем коде, как показано здесь:
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
int main() {
int fd[2], p;
char *m = "123456789\n", c;
pipe(fd);
p = fork();
if (p == 0) {
// child
close(fd[1]); // <--- this close is fundamental for the pipe to work properly.
while(read(fd[0], &c, 1) > 0) write(1, &c, 1);
}
else if (p > 0) {
// parent
// another close(fd[0]); should be included here
write(fd[1], m, strlen(m));
close(fd[1]);
wait(NULL);
} else {
// include error processing for fork() here
}
exit (0);
}