Я пишу программу на С, что данные исполняемым a.out
и входные файлами in_1.txt
, in_2.txt
... in_n.txt
, будет работать a.out
на всех n
входных файлы и будет производить соответствующий вывод для каждого входного файла в списке аргументов.
Я натолкнулся на какое-то странное поведение из своей программы (назовите его tester.out
), и через пару часов я смог идентифицировать свою проблему, но не мог понять, что решить.Проблемы со связью между родительским-процессом и ребенком-процессом с использованием трубы
Я первый разместим код, а затем объясню проблему ...
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<limits.h>
#include<string.h>
#define PERM S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP // 660
int main(int argc, char* argv[]) {
if (argc<3) {
printf("Arguments required; an executable file and at least one input file.\n");
return 1;
}
int channel[2];
if (pipe(channel)<0) {
perror("pipe");
return 1;
}
int i;
for (i=2; i<argc; ++i) {
pid_t p=fork();
if (p<0) {
perror("fork");
return 1;
}
if (p) { // parent
// closing read end
close(channel[0]); // *** The problem lies here! ***
int indicator;
if ((indicator=write(channel[1], argv[i], strlen(argv[i])+1))<0) {
perror("write");
return 1;
}
printf("Parent wrote %d bytes\n", indicator);
int status;
wait(&status);
if (WIFEXITED(status)) {
printf("Your program terminated normally with exit code %d\n", WEXITSTATUS(status));
printf("See output file: %s_output\n", argv[i]);
}
else if (WIFSIGNALED(status)) {
printf("Your program terminated by a signal! signal code: %d\n", WTERMSIG(status));
}
}
else { // child
// closing write end
close(channel[1]);
char input_file[PATH_MAX]={0};
char output_file[PATH_MAX+10]={0};
int indicator;
// read input_file from pipe
if ((indicator=read(channel[0], input_file, PATH_MAX))<1) {
perror("child process: read");
return 1;
}
printf("child read %d bytes\n", indicator);
sprintf(output_file, "%s_output", input_file);
printf("Got %s and output is %s\n", input_file, output_file);
sleep(5); /* later, I will call execl() here to run argv[1] on input_file */
return 1;
}
}
return 0;
}
Это работает, как ожидалось, когда я бегу:
$ ./tester.out a.out input1.txt
Но терпит неудачу, когда я запускаю его с более одного входного файла:
$ ./tester.out a.out input1.txt input2.txt
Как видно из выделенного комментария в коде, проблема заключается в линии вызова к close(channel[0])
, поскольку закрытию channel[0]
в родительском на первой итерации, означает, что на второго итерации, дочерний процесс имеет свой channel[0]
закрыт (его родители - в первой итерации).
Любые предложения о том, как решить эту ситуацию?
Эта строка: if (argc <3) {требуется не менее 2 входных файлов, предположим: if (argc <2) { – user3629249
нет, строка if (argc <3) требует не менее 1 входного файла. argv [0] зарезервирован, argv [1] содержит исполняемый файл, а argv [2] содержит первый входной файл. –