Перенаправить stdout из двух процессов в другой процесс stdin в Linux C

Я столкнулся с проблемой перенаправления stdout для нескольких процессов.

Предполагая, что у меня есть процесс A, я использую fork() в A, а затем я получаю процесс A и B. И я использую fork() в B, наконец, я получаю процесс A, B и C. Оба B и C реализуют другой программой exec().

Теперь я пытаюсь перенаправить stdout из A и B в stdin из C с двумя трубами.

#include<unistd.h>
#include<stdio.h>
#include<sty types.h="">
int main()
{
 int AtoC [2];
 pipe(AtoC);
 int fd1,fd2;
 fd1=fork();
 if(fd1>0)
 {
 /***In process A, I do the following steps: ***/
 close(AtoC[0]);
 dup2(AtoC[1], STDOUT_FILENO);
 /* program running in process A */
 }
 else
 {
 int BtoC [2];
 pipe(BtoC);
 fd2=fork();
 if(fd2>0)
 {
 /***In process B, I do the following steps: ***/
 close(AtoC[1]);
 close(BtoC[0]);
 dup2(BtoC[1], STDOUT_FILENO);
 /*** execute another program in process B using execl(); ***/
 }
 else
 {
 /*** In process C, I do the following steps: ***/
 close(AtoC[1]);
 close(BtoC[1]);
 dup2(AtoC[0],STDIN_FILENO);
 dup2(BtoC[0],STDIN_FILENO);
 /*** execute another different program in process C using execl(); ***/
 }
 }
}
</sty></stdio.h></unistd.h>

Теперь, после этих двух утверждений:

dup2(AtoC[0],STDIN_FILENO);
dup2(BtoC[0],STDIN_FILENO);

stdin процесса C окончательно перенаправляется на BtoC[0], который является этапом процесса B. И stdout процесса A не передается в процесс C stdin.

Мой вопрос заключается в том, есть ли какое-либо решение, позволяющее мне одновременно перенаправить оба процесса A и B stdout в процесс C stdin.

Другой вопрос, если я также хочу напечатать stdout процесса A на экране, что мне делать? Я знаю команду tee в командной строке. Я пытаюсь использовать соответствующую функцию tee(int fd_in, int fd_out, size_t len, unsigned int flags) в процессе A, но мне не удалось распечатать что-либо из процесса процесса A.

Любое предложение приветствуется, спасибо.

4 ответа

Я не уверен, что это хорошая идея, но это вполне осуществимо. Главное наблюдение заключается в том, что вам нужна только одна труба. Несколько процессов (с общим родителем) могут записываться в один канал. Однако в качестве стандартного ввода можно использовать только один дескриптор файла. В исходном коде только один из каналов был подключен к C в качестве стандартного входа (остальные все еще были связаны, но главным образом потому, что вы не закрыли достаточно дескрипторов).

  • Правило: если вы подключаете один конец канала к стандартным входам или стандартным выводам через dup2() (или dup()), вы должны закрыть оба дескриптора файла, возвращенные pipe().

Попробуйте этот код для размера. Я уменьшил кустистость дерева, удалил неиспользуемые переменные (ничто не использует идентификаторы процессов, возвращаемые fork()), переименовал канал, убедился, что он закрыт должным образом в каждом процессе и предоставил некоторую активность записи в процессах A и B и некоторые операции чтения в процессе C вместо запуска команд. Я предполагаю, что usleep() (микро-сон, время сна, выраженное в микросекундах) доступно; если нет, попробуйте nanosleep(), но он имеет более сложный интерфейс).

#include <unistd.h>
int main(void)
{
 int ABtoC[2];
 pipe(ABtoC);
 if (fork() > 0)
 {
 // Process A
 close(ABtoC[0]);
 dup2(ABtoC[1], STDOUT_FILENO);
 close(ABtoC[1]); // Close this too!
 // Process A writing to C
 for (int i = 0; i < 100; i++)
 {
 write(STDOUT_FILENO, "Hi\n", sizeof("Hi\n")-1);
 usleep(5000);
 }
 }
 else if (fork() > 0)
 {
 // Process B
 close(ABtoC[0]);
 dup2(ABtoC[1], STDOUT_FILENO);
 close(ABtoC[1]);
 // Process B writing to C
 for (int i = 0; i < 100; i++)
 {
 write(STDOUT_FILENO, "Lo\n", sizeof("Lo\n")-1);
 usleep(5000);
 }
 }
 else
 {
 char buffer[100];
 ssize_t nbytes;
 close(ABtoC[1]);
 dup2(ABtoC[0], STDIN_FILENO);
 close(ABtoC[0]);
 // Process C reading from both A and B
 while ((nbytes = read(STDIN_FILENO, buffer, sizeof(buffer))) > 0)
 write(STDOUT_FILENO, buffer, nbytes);
 }
 return(0);
}
</unistd.h>

Хвост конца прогона на моем Mac (Mac OS X 10.7.5, GCC 4.7.1):

Lo
Hi
Lo
Hi
Lo
Hi
Lo
Hi
Lo
Hi
Hi
Lo
Lo
Hi
Hi
Lo
Hi
Lo
Hi
Lo
Hi
Lo
Hi
Lo
Lo
Hi


После совместного использования труб вы можете проверить is-it-safe-to-pipe-the-output-of-several-parallel-processes. Не работает проблема для небольших записей, но для больших данных можно получить чередование =)


как перенаправить два конца выходных труб на один конец входного канала.

Я не знаю, как это работает, и ждет других ответов на op. Однако, альтернативно, вы можете использовать асинхронный ввод-вывод epoll. Процесс A не должен блокироваться на выходе процесса B/C. Процесс А читается, когда доступны данные.

Мне не удалось распечатать что-либо из процесса процесса А.

На странице man есть хороший пример использования tee, только для вашей справки.


Это невозможно. Вся идея о трубе состоит в том, что он имеет 2 конца - один прикреплен к вашему процессу, скажем, процесс A, а другой относится к другому процессу, например C. Если какой-либо другой процесс хочет создать еще один канал, он должен также иметь 2 конца, и невозможно, чтобы два конца кончились в одном отверстии.

Когда вы это сделали:

dup2(AtoC[0],STDIN_FILENO);
dup2(BtoC[0],STDIN_FILENO);

вторая строка эффективно перекрывает первую. dup2 (oldfd, newfd) должен закрыть newfd и сделать его таким же, как oldfd. Итак, первая строка подключает его, но вторая строка отключает его и вставляет что-то другое.

licensed under cc by-sa 3.0 with attribution.