【问题标题】:How do I chain stdout in one child process to stdin in another child in C?如何在 C 中将一个子进程中的标准输出链接到另一个子进程中的标准输入?
【发布时间】:2011-11-09 01:27:47
【问题描述】:

我一直在 C 语言中乱搞,试图弄清楚如何做到这一点。假设我有我的主程序,即父进程。父进程创建了三个子进程,每个子进程最终都会运行程序(但现在这并不重要)。我想做的是让第二个孩子的标准输入接收到第一个孩子的标准输出。然后第二个孩子的标准输出将被第三个孩子的标准输入接收。 父进程的 stdin/stdout 一点也不乱。

到目前为止,我得到的是

pipe(procpipe);

parentPid = getpid();

for(i = 0; i < 3; i++)
{
    if(getpid() == parentPid)
    {
        child[i] = fork();
        if(child[i] == 0)
        {
            mynumber = i+1;
        }
    }
}

但是从那里我有点卡住了如何使用 dup2 正确分配我的管道,以及在我的代码的哪个部分插入它。谷歌和这个网站上有很多关于如何从父母到孩子的管道示例,但我还没有看到一个能够准确告诉我如何将孩子的标准输出连接到另一个孩子的标准输入的例子。

编辑: 忘了提一下:假设我的所有变量都已正确初始化。 int 'mynumber' 是一个子进程在创建时知道它是哪个数字,所以我可以通过

给它指示
if(mynumber == whatever)

【问题讨论】:

标签: c process stdout pipe stdin


【解决方案1】:

因此,您有一个创建多个子进程的循环。这些子进程中的每一个都将使用 两个 管道:从上一个读取并写入到下一个。要为读取端设置管道,您需要关闭管道的写入端,并将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 时,将有四个打开的文件描述符:两个在父进程上,另外两个在子进程上。你必须关闭所有你不会使用的。这就是为什么上面的代码总是关闭子进程中管道的不相关端,并且两端都在父进程中。

另外请注意,我对第一个和最后一个过程进行了特殊处理,因为我不知道链的输入从哪里来,输出到哪里。

【讨论】:

  • 这是很多很棒的代码,谢谢!第一个孩子从正常的标准输入中获取输入,所以是的,这很好。我还在玩,所以我想我会尝试让我的最后一个管道写入文件。希望我能在没有太多外部帮助的情况下做到这一点。
  • 当我在我制作的 shell 中使用这些函数时(一个 while 循环询问输入并使用上面的函数处理它)我得到一个无限循环。什么原因?
猜你喜欢
  • 1970-01-01
  • 2023-04-02
  • 2013-06-25
  • 2018-05-04
  • 2010-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多