Возможно ли иметь канал между двумя дочерними процессами, созданными одним и тем же родителем (LINUX, POSIX)

у меня есть несколько дочерних "раздвоенных" одним и тем же родителем, и я пытаюсь построить pipe связь между всеми этими дочерними процессами, такими как структура связанного списка. Ребенок 1 отправляет данные ребенку 2, ребенок 2 ребенку 3.... ребенок N ребенку 1. Есть ли правильный способ сделать это?

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

спасибо...

3 ответов


это по существу то, что делает оболочка, если построить цепь перенаправления, то есть что-то вроде

ls | grep foo | sort | uniq

есть несколько прекрасных introducionary текстов по программированию в Unix, в котором простой оболочки реализуется через книгу. И одна из задач оболочки перенаправление. Одной из таких книг является "Linux Application Programming" Майкла К. Джонсона и Эрика У. Троана.

Домашняя страница книги:http://ladweb.net/

для постройте цепочку перенаправлений для N процессов, вам нужно N-1 труб. Для каждого перенаправления вы создаете канал с помощью pipe(int fds[2]) системный вызов. После fork()ing, но до execving использовать dup2(int from, int to) "подключить" конец трубы к стандартному входу (0) или стандартному выходу каждого процесса. Вот чрезмерно упрощенный код, без проверки ошибок:

int pipe_A[2];
int pipe_B[2];

pipe(pipe_A);
pipe(pipe_B);

pid_t pid_A, pid_B, pid_C;

if( !(pid_A = fork()) ) {
    dup2(pipe_A[1], 1); /* redirect standard output to pipe_A write end */
    execv(...);
}

if( !(pid_B = fork()) ) {
    dup2(pipe_A[0], 0); /* redirect standard input to pipe_A read end */
    dup2(pipe_B[1], 1); /* redirect standard output to pipe_B write end */
    execv(...);
}

if( !(pid_C = fork()) ) {
    dup2(pipe_B[0], 0); /* redirect standard input to pipe_B read end */
    execv(...);
}

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

конечно, вы можете подключать каналы к любым файловым дескрипторам (например, есть некоторые приложения, которые ожидают, что их родитель откроет, скажем, fd 3 и 4, подключенные к трубам), и большинство оболочек напрямую поддерживают это (например, 1>&3 перенаправит stdout в fd 3). Однако индексы массива для pipe(int fds[2]) 0 и 1 конечно. Я просто рассказываю это, потому что у меня были студенты-карго-культовые программисты, которые бездумно взял целевой fds также для массива syscall трубы.

ждать, пока все дети закончат использовать waitpid(-1, NULL, 0) – Я думаю, что это -1 мой предварительный ответ, который означает: дождитесь завершения всех дочерних процессов. Другим вариантом был вызов wait() в цикле, который вернет pid только что завершенного ребенка. Если и есть еще ребенок работает, он может снова заблокировать. Если ребенка не осталось, он вернется -1; Я предпочитаю waitpid решение.


Да, это довольно легко, вам просто нужно создать все трубы в родителе и не забудьте закрыть трубы / концы труб в дочернем(ren), которые вам не нужны.

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


сначала создайте все трубы, затем создайте всех детей с соответствующими концами труб в FDs 0 и 1.

Что касается ожидания, просто продолжайте ждать, пока он не вернет -1.