2016-11-14 1 views
0

Я пытаюсь написать программу в C, которая создает 2 дочерних процесса, каждый из которых выполняет execvp.Проблема с трубкой: первый ребенок слишком много пишет в трубку

Моя проблема заключается в том, что первый ребенок записывает слишком большой объем ввода в трубу, из которой читается другой ребенок.

int main(int argc, char* argv[]){ 

//unnamed pipe 
int pipeFd[2], statusFirst,statusSecond; 
pid_t childPidOne,childPidTwo; 

if(pipe(pipeFd) < 0){ 
    perror("Pipe error:\n"); 
    exit(EXIT_FAILURE); 
} 

switch(childPidOne = fork()){ 
    case -1: 
     perror("First Fork error:\n"); 
     exit(EXIT_FAILURE); 
    case 0: 
     printf("First child\n"); 
     close(pipeFd[1]); 
     if((execvp(argv[1], &argv[1])) < 0){ 
      perror("First execvp error:\n"); 
     } 
     printf("End First cild\n"); 
     exit(0); 
    default: 
     //Do nothing 
     break; 
} 

switch(childPidTwo = fork()){ 
    case -1: 
     perror("Second Fork error:\n"); 
     exit(EXIT_FAILURE); 
    case 0: 
     printf("Second cild\n"); 
     close(pipeFd[0]); 
     if((execvp(argv[3], &argv[3])) < 0){ 
      perror("Second execvp error:\n"); 
     } 
     printf("End Second cild\n"); 
     exit(0); 
    default: 
     //Do nothing 
     break; 
} 


close(pipeFd[0]); 
close(pipeFd[1]); 


if((waitpid(childPidOne,&statusFirst,WUNTRACED | WCONTINUED)) < 0){ 
    perror("First waitpid error:\n"); 
}else{ 
    if (WIFEXITED(statusFirst)) { 
     printf("First exited, status=%d\n", WEXITSTATUS(statusFirst)); 
    } else if (WIFSIGNALED(statusFirst)) { 
     printf("First killed by signal %d\n", WTERMSIG(statusFirst)); 
    } else if (WIFSTOPPED(statusFirst)) { 
     printf("First stopped by signal %d\n", WSTOPSIG(statusFirst)); 
    } else if (WIFCONTINUED(statusFirst)) { 
     printf("First continued\n"); 
    } 
} 


if((waitpid(childPidTwo,&statusSecond,WUNTRACED | WCONTINUED)) < 0){ 
    perror("Second waitpid error:\n"); 
} 
if (WIFEXITED(statusSecond)) { 
    printf("Second exited, status=%d\n", WEXITSTATUS(statusSecond)); 
    } else if (WIFSIGNALED(statusSecond)) { 
    printf("Second killed by signal %d\n", WTERMSIG(statusSecond)); 
    } else if (WIFSTOPPED(statusSecond)) { 
    printf("Second stopped by signal %d\n", WSTOPSIG(statusSecond)); 
    } else if (WIFCONTINUED(statusSecond)) { 
     printf("Second continued\n"); 
     } 

    exit(0); 
return 0; 
    } 

Может быть, у меня есть неправильное понимание того, как труба + вилка + execvp работы, поэтому позвольте мне сказать вам, что я делаю в моем коде:

  1. создать неназванный трубу - оба Чайлдс использовать та же труба
  2. Я создам две Чайлдс по разветвление их
  3. Поскольку я выполняю свою программу, как это: ./pipeline [FIRST SYSTEM CALL] | [SECOND SYSTEM CALL] или просто чтобы дать вам пример: ./pipeline echo Hello | wc -m я закрываю сайт чтения трубы
  4. А затем вызвать execvp(argv[1], &argv[1])

И это, где происходит ошибка (я думаю): Я никогда не закрывая сторону письма, пока второй ребенок не делает, потому что execvp никогда не вернется, если это удастся.

И я знаю, что execvp не закрывает дескрипторы открытых файлов (его можно закрыть, используя флаг в fcntl, как указано в What does the FD_CLOEXEC flag do?).

Пример

Позвольте привести пример.

echo Hello | wc -m 

выводит результат

Поскольку система вызова wc (количество слов) подсчитывает символы (-m) в данном String

Это правильно, потому что hello = 5 + 1 (это \n или \0 Я думаю) и это составляет 6.

Теперь работает моя программа дает результат

или получить более подробную информацию

echo hello | wc 

выходы

1 (линия) 1 (слово) 6 (символы)

И ./pipeline echo hello | wc

выходы

3 (линия) 9 (слово) 56 (символы)

Я искал в течение нескольких дней, но я не могу понять вне.

Любые идеи?

Большое спасибо!

+1

Если вы используете './pipeline echo hello | wc', чтобы запустить вашу программу, тогда это не делает то, что вы думаете. Ваша программа видит 'argv [1] == echo',' [2] == hello' и _nothing else_. (Комбинированный) вывод вашей программы затем передается в 'wc'. Чтобы (полностью) достичь того, что, как я думаю, вы хотите сделать, вам нужно избежать символа трубы и обнаружить его в вашем коде (чтобы вы знали, какие части командной строки переходят в каждый дочерний процесс). – TripeHound

+0

@TripeHound, я избежал символа вручную, набрав ./pipeline echo hello \ | wc, и это сработало для меня, за исключением того, что второй ребенок запускает wc в интерактивном режиме (ждет ввода и ctrl + d, чтобы отметить конец ввода). Это дает мне правильный результат 1 1 6. Это означает, что вход первого ребенка игнорируется. Есть идеи ? –

ответ

0

Решил сам.

Забыл использовать dup2.

Просто введите команду dup2 после команды close, и с вами все будет в порядке.