Трубопроводные команды bash echo и bc в программу на C - PullRequest
0 голосов
/ 17 мая 2019

Я пытаюсь создать небольшую C-программу, которая реализует конвейер из двух команд bash: echo $ arithmeticOperation | до н.э.

$ arithmeticOperation - строка, взятая в качестве входных данных.

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

Итак, в этой строке родительский процесс заблокирован: waitpid (ПИД2, NULL, 0);

Как вы думаете, где может быть проблема?

Извините, если я задал вопрос неправильно, это мой первый вопрос. Спасибо.



    #define SYSCALL(r,c,e) if((r=c)==-1) { perror(e);exit(EXIT_FAILURE);}

    int main(){
        char buf[128];
        int pfd[2],err;
        pid_t pid1,pid2;
        SYSCALL(err,pipe(pfd),"pipe");
        switch (pid1=fork()) {
            case -1: { perror("fork"); exit(EXIT_FAILURE);}
            case 0 : { 
                scanf("%s",buf);
                SYSCALL(err,dup2(pfd[1],1),"dup");
                close(pfd[1]);
                close(pfd[0]);
                execl("/bin/echo","echo",buf,(char *)NULL);
                return 1;
            }   
        }   
        switch (pid2=fork() ){
             case -1 : { perror("fork"); exit(EXIT_FAILURE);}
             case 0 : { 
                 SYSCALL(err,dup2(pfd[0],0),"dup");
                 close(pfd[1]);
                 close(pfd[0]);
     //          execl("/usr/bin/bc","bc",(char *)NULL);
                 execlp("bc","bc",(char *)NULL);
                return 1;
            }   
        }   
    printf("waiting . . . \n");
    waitpid(pid1,NULL,0);
    printf("wait\n");
    waitpid(pid2,NULL,0);
    close(pfd[1]);
    close(pfd[0]);
    return 0;
    }

Так что, если я наберу цифру "1 + 1" в качестве входной строки, я получу правильный вывод, но тогда процесс, выполняющий bc, никогда не завершится

1 Ответ

0 голосов
/ 17 мая 2019

Как я отмечал в комментарии , ваш родительский процесс должен закрыть файловые дескрипторы для канала до ожидания bc (и вы согласились, что это решает проблему).

Это происходит потому, что bc имеет канал, открытый для чтения, и родительский канал имеет канал, открытый для записи, и ядро ​​считает, что родитель может поэтому отправить данные в bc.Это не так, но могло бы.

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


Правило большого пальца : если вы dup2() один конецДля перехода к стандартному вводу или стандартному выводу закройте оба исходных файловых дескриптора, возвращенных pipe(), как можно скорее.В частности, вы должны закрыть их перед использованием любого из семейства функций exec*().

Правило также применяется, если вы дублируете дескрипторы с dup() или fcntl() с F_DUPFD


Мне нужно расширить это также на родительские процессы.

Если родительский процесс не будет связыватьсяс любым из его дочерних элементов через канал он должен убедиться, что он закрывает оба конца канала, чтобы его дочерние элементы могли получать показания EOF при чтении (или получать сигналы SIGPIPE или ошибки записи при записи), а не блокировать бесконечно.Родитель обычно должен закрыть хотя бы один конец канала - для программы было бы крайне необычно читать и писать на обоих концах одного канала.

...