Судя по коду, это проблема XY (изменить: переместить это раздел впереди из-за комментария, подтверждающего это). Если цель состоит в том, чтобы получить статус выхода дочернего элемента, то для этого есть значение, которое wait
возвращает, и каналы не требуются:
int stat;
wait(&stat);
Прочитайте руководство wait
, чтобы понять, как его читать. Значение stat
можно проверить следующим образом:
- WEXITSTATUS(stat) — если WIFEXITED(stat) != 0, то это младшие 8 бит дочернего вызова
exit(N)
или возвращаемое значение из main
. Он может работать корректно без проверки WIFEXITED, но в стандарте это не указано.
- WTERMSIG(stat) — если WIFSIGNALED(stat) != 0, то это номер сигнала, вызвавший завершение процесса (например, 11 — ошибка сегментации). Он может работать корректно без проверки WIFSIGNALED, но в стандарте это не указано.
В коде есть несколько ошибок. Смотрите добавленные комментарии:
void Command::fork_helper() {
// File descriptors here: 0=stdin, 1=stdout, 2=stderr
//(and 3..N opened in the program, could also be none).
bool return_type_child = true;
int fd[2];
pipe(fd);
// File descriptors here: 0=stdin, 1=stdout, 2=stderr
//(and 3..N opened in the program, could also be none).
// N+1=fd[0] data exhaust of the pipe
// N+2=fd[1] data intake of the pipe
pid_t child;
char *const argv[] = {"zf","-la", nullptr};
child = fork();
if (child > 0) {
// This code is executed in the parent.
wait(NULL); // wait for the child to complete.
Это wait
является потенциальным тупиком: если дочерний элемент записывает в канал достаточно данных (обычно в килобайтах) запись блокируется и ждет, пока родитель прочитает канал. Родительское ожидание (NULL) ожидает завершения дочернего элемента, который ждет, пока родитель прочитает канал. Это, вероятно, не влияет на рассматриваемый код, но проблематично.
close(0);
close(fd[1]);
dup(fd[0]);
// File descriptors here: 0=new stdin=data exhaust of the pipe
// 1=stdout, 2=stderr
// (and 3..N opened in the program, could also be none).
// N+1=fd[0] data exhaust of the pipe (stdin is now a duplicate)
Это проблематично, поскольку:
- код только что потерял исходный стандартный ввод.
- Труба никогда не закрывается. Вы должны закрыть fd[0] явно, не закрывать (0) и не дублировать fd[0].
- Рекомендуется избегать дублирования дескрипторов, за исключением дублирования stderr stdout.
.
bool return_type_parent = read(fd[0], &return_type_child, sizeof(return_
this->return_type = return_type_parent;
}
else if (child == 0) {
// this code runs in the child.
close(fd[0]);
close(1);
dup(fd[1]);
// File descriptors here: 0=stdin, 1=new stdout=pipe intake, 2=stderr
//(and 3..N opened in the program, could also be none).
// N+2=fd[1] pipe intake (new stdout is a duplicate)
Это проблематично, так как в канал поступает два дублирующих данных. В данном случае это не критично, так как они оба закрываются автоматически по завершении процесса, но это плохая практика. Это плохая практика, так как только закрытие всех воздухозаборников сигнализирует END-OF-FILE выхлопу. Закрытие одного входа, но не другого, не сигнализирует КОНЕЦ ФАЙЛА. Опять же, в вашем случае это не вызывает проблем, так как выход ребенка закрывает все входы.
execvp(argv[0], argv);
Код ниже приведенной выше строки никогда не достигается, если только сам execvp
не дал сбой. execvp
завершается ошибкой только в том случае, если файл не существует или у вызывающей стороны нет разрешения на его выполнение. Если исполняемый файл начинает выполняться и позже завершается ошибкой (возможно, даже если ему не удается прочитать разделяемую библиотеку), то сам execvp
все равно завершается успешно и никогда не возвращается. Это связано с тем, что execvp
заменяет исполняемый файл, а следующий код больше не находится в памяти, когда execvp
запускает другую программу.
this->return_type = false;
return_type_child = false;
write(1,&return_type_child,sizeof(return_type_child));
}
return;
}
person
Michael Veksler
schedule
17.02.2019
fd[0]
в родителя. Кроме того, еслиexecvp
завершается успешно, кто или что записывает возвращаемую информацию в родителя? - person David Schwartz   schedule 17.02.2019