2014-11-28 3 views
0

Я пишу программу на С, что данные исполняемым 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] закрыт (его родители - в первой итерации).

Любые предложения о том, как решить эту ситуацию?

+0

Эта строка: if (argc <3) {требуется не менее 2 входных файлов, предположим: if (argc <2) { – user3629249

+0

нет, строка if (argc <3) требует не менее 1 входного файла. argv [0] зарезервирован, argv [1] содержит исполняемый файл, а argv [2] содержит первый входной файл. –

ответ

1

Вы должны создать новый канал для каждого дочернего процесса и закрыть оба конца трубы, когда вы закончите с ним. Вам нужно закрыть оба конца как в родительском, так и в дочернем.

+0

Итак, вызов pipe() должен находиться внутри цикла for прямо перед fork()? –

+0

Хорошо, да. Он работает так, как ожидалось. Благодаря! –

0

Простое исправление будет:

Переход от до цикла, чтобы внутри цикла, непосредственно перед линией, которая вызывает вилку(). Затем определите переменную выбора [2] и выполните вызов pipe().

Смежные вопросы