У меня есть несколько конкретных комментариев к вашему коду:
char *c = (char *)malloc(sizeof(char));
Хотя в этом нет ничего плохого, также нет необходимости выделять это char
из кучи. Более идиоматический подход будет использовать char c;
здесь и затем передавать &c
на read(2)
и write(2)
системные вызовы. (Еще более идиоматично было бы использовать стандартное средство ввода-вывода C; freopen(3)
, getchar(3)
и putchar(3)
- но не делайте этот переход, пока у вас не работает этот код точно так, как вы хотите, потому что он дополнительное осложнение проблемы, которую вы пытаетесь решить.)
if ((pid1 = fork()) < 0) {
printf("Eroare la fork\n");
exit(1);
}
Используя собственное сообщение об ошибке, вы упускаете важную информацию об ошибке. Вы должны использовать perror(3)
, чтобы напечатать сообщение об ошибке. Это даст вам и вашим пользователям фактическую причину ошибок, которые они могут искать. fork(2)
может произойти сбой, если ваш пользователь запускает максимальный предел процесса setrlimit(2)
NPROC
, общесистемный предел процесса, из памяти ядра.
if ((pid1 = fork()) < 0) {
perror("Eroare la fork");
exit(1);
}
Вам также следует проверить возвращаемое значение из open(2)
вызовов. (Вы должны также проверить возвращаемые значения из write(2)
и close(2)
на наличие ошибок, но обработка этих ошибок сложнее. Просто распечатка ошибки и выход из нее - хороший старт для большинства программ.)
while (read(pfd1[0], c, 1) > 0) {
//printf("%s",c);
if (islower(*c)) {
close(pfd2[0]);
Это неправильное расположение для вызова close(2)
- вам не следует закрывать этот файловый дескриптор снова и снова для каждого входного символа. Если бы вы проверяли возвращаемое значение close(2)
, вы бы заметили, что errno
установлено на EBADF
, поскольку дескриптор файла больше не действует при втором и последующих вызовах.
Теперь перейдем к проблеме, для которой вы пришли: последовательность вызовов fork()
, pipe()
и dup2()
, которые подключат все ваши процессы в конвейере и отправят данные обратно в родительский процесс. Так как pipe(2)
создает однонаправленные pipe(7)
s, вам нужно позвонить pipe(2)
четыре раза - для обоих направлений между родителем и детьми. Если вы храните конечные точки канала в массивах с именами, которые что-то для вас значат, их будет легче отслеживать. Возможно, создайте массивы с именем to_
для записи и from_
для чтения из:
int to_child[2];
int from_parent[2];
int to_parent[2];
int from_child[2];
for (int i=0; i<2; i++) {
int p[2];
if (pipe(p) == -1) {
perror("pipe");
exit(1);
}
/* from parent to child */
to_child[i] = p[1];
from_parent[i] = p[0];
if (pipe(p) == -1) {
perror("pipe");
exit(1);
}
/* from child to parent */
to_parent[i] = p[1];
from_child[i] = p[0];
}
Обратите внимание, что на самом деле не требуется для использования dup2(2)
для перестановки файловых дескрипторов, если вы не хотите выполнить других программ для обработки задачи "фильтра". Просто read(2)
с использованием дескрипторов from_parent[...]
или from_child[...]
и write(2)
для дескрипторов to_child[...]
и to_parent[...]
.
Может быть, все было бы проще с socketpair(2)
с использованием AF_UNIX
для создания двунаправленных сокетов , которые затем можно читать и записывать таким же образом, как и любой другой стиль BSD разъем. См. socket(7)
и unix(7)
для обзора.