Итак, у вас есть цикл, который создает несколько дочерних процессов.Каждый из этих дочерних процессов будет использовать два канала: читать из предыдущего и записывать в следующий.Чтобы настроить канал для конца чтения, вам нужно закрыть конец записи канала и dup2
конец чтения в стандартный ввод.Аналогично для трубы, в которую будет записываться процесс.
void set_read(int* lpipe)
{
dup2(lpipe[0], STDIN_FILENO);
close(lpipe[0]); // we have a copy already, so close it
close(lpipe[1]); // not using this end
}
void set_write(int* rpipe)
{
dup2(rpipe[1], STDOUT_FILENO);
close(rpipe[0]); // not using this end
close(rpipe[1]); // we have a copy already, so close it
}
Когда вы разветвляете каждого потомка, вам нужно прикрепить к нему трубы.
void fork_and_chain(int* lpipe, int* rpipe)
{
if(!fork())
{
if(lpipe) // there's a pipe from the previous process
set_read(lpipe);
// else you may want to redirect input from somewhere else for the start
if(rpipe) // there's a pipe to the next process
set_write(rpipe);
// else you may want to redirect out to somewhere else for the end
// blah do your stuff
// and make sure the child process terminates in here
// so it won't continue running the chaining code
}
}
Имея это в руках, вы можете теперьнаписать цикл, который непрерывно разветвляется, присоединяет каналы, а затем повторно использует выходной канал в качестве входного канала для следующего.Конечно, как только оба конца канала подключены к дочерним процессам, родительский элемент не должен оставлять его открытым для себя.
// This assumes there are at least two processes to be chained :)
// two pipes: one from the previous in the chain, one to the next in the chain
int lpipe[2], rpipe[2];
// create the first output pipe
pipe(rpipe);
// first child takes input from somewhere else
fork_and_chain(NULL, rpipe);
// output pipe becomes input for the next process.
lpipe[0] = rpipe[0];
lpipe[1] = rpipe[1];
// chain all but the first and last children
for(i = 1; i < N - 1; i++)
{
pipe(rpipe); // make the next output pipe
fork_and_chain(lpipe, rpipe);
close(lpipe[0]); // both ends are attached, close them on parent
close(lpipe[1]);
lpipe[0] = rpipe[0]; // output pipe becomes input pipe
lpipe[1] = rpipe[1];
}
// fork the last one, its output goes somewhere else
fork_and_chain(lpipe, NULL);
close(lpipe[0]);
close(lpipe[1]);
Закрывающие биты очень важны!Когда вы работаете с открытым каналом, будет четыре дескриптора открытого файла: два в родительском процессе и два других в дочернем процессе.Вы должны закрыть все те, которые вы не будете использовать.Вот почему приведенный выше код всегда закрывает нерелевантные концы каналов в дочерних процессах, и оба конца на родительских процессах.
Также обратите внимание, что я обращаю особое внимание на первый и последний процессы, потому что я надеваюне знаю, откуда поступит вход для цепочки, и куда пойдет выход.