因此,您有一个创建多个子进程的循环。这些子进程中的每一个都将使用 两个 管道:从上一个读取并写入到下一个。要为读取端设置管道,您需要关闭管道的写入端,并将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]);
结束位非常重要!当您使用打开的管道进行 fork 时,将有四个打开的文件描述符:两个在父进程上,另外两个在子进程上。你必须关闭所有你不会使用的。这就是为什么上面的代码总是关闭子进程中管道的不相关端,并且两端都在父进程中。
另外请注意,我对第一个和最后一个过程进行了特殊处理,因为我不知道链的输入从哪里来,输出到哪里。