Чтобы узнать, как работает механизм Pipe IPC, я написал простую программу, которая создает два дочерних процесса, которые обмениваются данными с помощью канала. Первый дочерний процесс должен прочитать данные из файла и передать их в канал.
После этого второй дочерний процесс должен прочитать его, преобразовать в верхний регистр и записать в другой файл. Системный вызов чтения во втором дочернем процессе возвращает -1 при чтении из канала. Также, когда я запускаю программу, в некоторых случаях printf в первом дочернем элементе ничего не печатается, а в других случаях printf во втором дочернем элементе тоже не печатается. Не могли бы вы указать ошибки в программе, которые вызывают проблемы?
int main(int args[], char * argv[]) {
int fd[2];
long length;
char buff1[250];
char buff2[250];
FILE * fptr1;
FILE * fptr2;
pid_t A, B;
pipe(fd);
A = fork();
if (A == -1) {
printf("error in fork of A\n");
exit(1);
}
if (A == 0) {
fptr1 = fopen(argv[1], "r"); // program receives file names as argument
if (fptr1 == NULL) {
printf("Erro in file open1\n");
exit(1);
}
fseek(fptr1, 0 L, SEEK_END);
length = ftell(fptr1);
fseek(fptr1, 0 L, SEEK_SET);
close(fd[0]);
fread(buff1, length, 1, fptr1);
buff1[length] = '\0';
printf("buff1 = %s", buff1);
write(fd[1], buff1, length);
fclose(fptr1);
exit(0);
} else {
B = fork();
if (B == -1) {
printf("Error in forking child B");
exit(1);
}
if (B == 0) {
fptr2 = fopen(argv[2], "w");
if (fptr2 == NULL) {
printf("Error in file open2\n");
exit(1);
}
close(fd[1]);
int n = read(fd[0], buff2, length);
printf("n = %d\n", n);
upper_string(buff2); // converts characters to uppecase
fwrite(buff2, 1, length, fptr2);
fclose(fptr2);
}
}
return 0;
}
Гораздо проще избежать такого рода проблем, если вы разделите пути родительского и дочернего кода (после fork) на разные функции. Иметь одну большую функцию с локальными переменными, объявленными вверху, но инициализируемыми только в некоторых путях кода, всегда проблематично.
О, и если read возвращает -1, вам стоит попробовать напечатать errno.
Настройка length для второго ребенка устранила неопределенное поведение. Также я добавил два вызова wait() в родительском процессе, чтобы теперь программа не зависала.





Здесь нужно учитывать несколько вещей. Первое, что я хотел бы отметить, это то, что вам не нужно использовать два вызова fork(). В этом случае у вас есть три процесса, работающих параллельно (родительский процесс и два дочерних процесса, по одному на каждый вызов fork()).
Один важный момент, который следует учитывать при работе с процессами, работающими параллельно, — это синхронность. В вашем коде вы создаете два процесса. Родительский процесс не ждет ни одного из своих дочерних процессов, поэтому он завершает свое выполнение, и если дочерние процессы не завершились, они станут дочерними для процесса инициализации. Но помимо этого у вас типичная проблема производителя-потребителя. Один ваш ребенок что-то производит, а другой это потребляет, но так как они работают параллельно, потребитель должен знать, что продукт готов к употреблению. Итак, в этом случае я думаю, что самый простой способ выполнить эту работу — использовать только одну fork(), чтобы дочерний процесс стал производителем, а родительский процесс (потребитель) ждал, пока его дочерний процесс закончит работу.
Кажется, что
lengthне определен во втором дочернем элементе, так как он нигде не установлен. Неопределенное поведение, может быть нулевым, если повезет, поэтому из канала ничего не читается.