Конвейеры Linux с использованием программирования C. Перенаправление входов/выходов через пайплайны

Я очень новичок в Linux, однако мне удалось сделать свою собственную оболочку. Пришло время добавить туда конвейеры. (Вот что, домашнее задание говорит). Может ли кто-нибудь объяснить мне немного больше, как это сделать? Я знаю, что в теории это должно работать так.

unsigned char* child_results; //buffer to save results from child processes

for (int i = 0; i < 2; i++) {
    pid = fork();

    if (pid == 0) {
        //if it's the first process to launch, close the read end of the pipe
        //otherwise read what the parent writes to the pipe and then close the 
        //read end of the pipe

        //call execvp()
    }
    else {
        //if you've launched the first process, close the write end of the pipe
        //otherwise write the contents of child_result to the child process
        //and then close the write end of the pipe

        //read from the child's pipe what it processed

        //save the results in the child_results buffer

        wait(NULL); //wait for the child to finish
    }
}

Однако я не могу заставить его работать. Я занимаюсь этим целый день и до сих пор ничего. Я понимаю идею, но не могу заставить ее работать. Может ли кто-нибудь помочь мне? Вот код моей части конвейера:

for (int i = 0; i <= pipeline_count; i++) { 
    int pdesc[2]; 
    // creating pipe
    pipe(pdesc);
    int b = fork();
    // child
    if (b == 0) {
        // 1st pipeline
        if (i == 0) {       
            //<?>               
        }

        // last pipeline
        if (i == pipeline_count) {                              
            //<?>
        }

        // inside pipeline
        if (i > 0 && i < pipeline_count)  {
            //<?>
        } 
        execvp(array[0], array);
    }
    else { 
        // parent
        //<?>
        wait(NULL);         
    }
}       

и вот пример команды оболочки

ls -al | tr a-z A-Z

Спасибо


person Patryk    schedule 10.11.2012    source источник
comment
Прочитайте advancedlinuxprogramming.com   -  person Basile Starynkevitch    schedule 11.11.2012
comment
Возможный дубликат реализации конвейерной обработки в C. Как лучше всего это сделать?   -  person jww    schedule 07.04.2019


Ответы (1)


Вы должны закрыть входной поток для дочернего элемента и продублировать с помощью dup канал для этого канала. Родитель делает то же самое с другой стороной трубы. Что-то вроде этого:

b = fork();
if (b == 0) {
  /* Close stdin, and duplicate the input side of the pipe over stdin */
  dup2(0, pdesc[0]);
  execlp(...);
}
else {
  /* Close stdout, and duplicate the output side of the pipe over stdout */
  dup2(1, pdesc[1]);
  execlp(...);
}
...

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

Надеюсь, это помогло!

person felixgaal    schedule 10.11.2012
comment
Почему я должен запускать execlp как в родительском, так и в дочернем процессе? Это не остановит мою программу? - person Patryk; 11.11.2012
comment
Нет! Конечно! Это всего лишь пример кода! Я просто показываю простой пример того, как вы должны использовать функцию dup2. В вашей ситуации вы должны вызывать dup2 для ввода в первом дочернем процессе, dup2 для вывода в последнем дочернем процессе и обе стороны в других промежуточных дочерних процессах. - person felixgaal; 11.11.2012
comment
Если бы Вы только сказали мне, как читать из канала в массив символов и записывать из массива символов в канал, я бы обязательно это сделал :P! - person Patryk; 11.11.2012
comment
Чтение из канала вручную, просто напишите int nbytes = read(pdesc[0], inbuf, sizeof(inbuf));. Для записи в канал используйте int nbytes = write(pdesc[1], outbuf, bytestowrite);. См. документы этих функций. - person felixgaal; 11.11.2012
comment
Но... Я не думаю, что это домашнее задание... Перечитайте, изучите, кусочки есть. Вы должны соединять процессы, а не отправлять данные из одного в другой. Вот что такое пайп: процессы читают и пишут в них. Вы просто соединяете их. - person felixgaal; 11.11.2012
comment
Ага, я тоже так думаю... А надо ли тогда 2 трубы? Потому что это невозможно, когда я пытаюсь сделать это на 1 канале (без чтения буфера) - person Patryk; 11.11.2012
comment
Вам нужно столько каналов, сколько | вы пишете в командной строке. Для ситуации, подобной ls | wc -l | lpr, вы должны использовать 2 канала и т. д. - person felixgaal; 11.11.2012