Я пытаюсь написать программу в 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 работы, поэтому позвольте мне сказать вам, что я делаю в моем коде:
- создать неназванный трубу - оба Чайлдс использовать та же труба
- Я создам две Чайлдс по разветвление их
- Поскольку я выполняю свою программу, как это:
./pipeline [FIRST SYSTEM CALL] | [SECOND SYSTEM CALL]
или просто чтобы дать вам пример:./pipeline echo Hello | wc -m
я закрываю сайт чтения трубы - А затем вызвать
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 (символы)
Я искал в течение нескольких дней, но я не могу понять вне.
Любые идеи?
Большое спасибо!
Если вы используете './pipeline echo hello | wc', чтобы запустить вашу программу, тогда это не делает то, что вы думаете. Ваша программа видит 'argv [1] == echo',' [2] == hello' и _nothing else_. (Комбинированный) вывод вашей программы затем передается в 'wc'. Чтобы (полностью) достичь того, что, как я думаю, вы хотите сделать, вам нужно избежать символа трубы и обнаружить его в вашем коде (чтобы вы знали, какие части командной строки переходят в каждый дочерний процесс). – TripeHound
@TripeHound, я избежал символа вручную, набрав ./pipeline echo hello \ | wc, и это сработало для меня, за исключением того, что второй ребенок запускает wc в интерактивном режиме (ждет ввода и ctrl + d, чтобы отметить конец ввода). Это дает мне правильный результат 1 1 6. Это означает, что вход первого ребенка игнорируется. Есть идеи ? –