【问题标题】:C Read stdout from multiple exec called from forkC从fork调用的多个exec中读取stdout
【发布时间】:2012-09-20 15:31:51
【问题描述】:

在下面的代码中,一个进程创建了一个子进程 (fork()),然后该子进程通过调用 exec() 替换自己。 exec 的 stdout 写在 pipe 而不是 shell 中。然后父进程从管道中读取 exec 用 while (read(pipefd[0], buffer, sizeof(buffer)) != 0)

写入的内容

有人能告诉我如何做与上述完全相同的事情,但有 N 个子进程(它们用上面的 exec 替换自己)。

int pipefd[2];
pipe(pipefd);

if (fork() == 0)
{
    close(pipefd[0]);    // close reading end in the child

    dup2(pipefd[1], 1);  // send stdout to the pipe
    dup2(pipefd[1], 2);  // send stderr to the pipe

    close(pipefd[1]);    // this descriptor is no longer needed

    exec(...);
}
else
{
    // parent

    char buffer[1024];

    close(pipefd[1]);  // close the write end of the pipe in the parent

    while (read(pipefd[0], buffer, sizeof(buffer)) != 0)
    {
    }
}

【问题讨论】:

  • 我没有时间输入完整的答案,但select() 是您正在寻找的功能——它会同时等待 N 个文件句柄并为您提供“准备好”文件句柄(“准备好”的意思是“不会在读取时阻塞或已在另一端关闭”)。
  • 孩子们需要同时写作吗?
  • 是的,他们需要同时写

标签: c exec fork pipe


【解决方案1】:

我找到了答案。我做了一个管道数组,这样一个进程就不会覆盖另一个进程的输出。

这是我的代码。有没有发现什么错误?

#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>

#define N 10

int main(int argc, char *argv[]) {
    ssize_t readlen;
    int pipefd[N][2];
    int i;
    for (i = 0; i < N; i++) {
        pipe(pipefd[i]);
    }

    int pid = getpid();

    for (i = 0; i < N; i++) {
        if (fork() == 0) //The parent process will keep looping
        {

            close(pipefd[i][0]);    // close reading end in the child

            dup2(pipefd[i][1], 1);  // send stdout to the pipe
            dup2(pipefd[i][1], 2);  // send stderr to the pipe

            close(pipefd[i][1]);    // this descriptor is no longer needed

            char b[50];
            sprintf( b, "%d", i);

            execl("/bin/echo", "echo", b,NULL);


        }
    }

    if (pid == getpid()) {

        // parent

        char buffer[1024];

        for (i = 0; i < N; i++) {
            close(pipefd[i][1]);  // close the write end of the pipe in the parent

            while ((readlen=read(pipefd[i][0], buffer, sizeof(buffer))) != 0)
            {
                        buffer[readlen] = '\0';
            }

            printf("%s\n",buffer);

        }
    }


}

【讨论】:

  • 任务如此简单,但代码太难了。祝你找到更简单的实现。
【解决方案2】:

也许这段代码可以完成这项工作:

const int N = 10; //Number of child processes
int pipefd[2];
pipe(pipefd);
int i;
for (i = 0; i < N; i++) {
    if (fork() == 0) //The parent process will keep looping
    {
        close(pipefd[0]);    // close reading end in the child

        dup2(pipefd[1], 1);  // send stdout to the pipe
        dup2(pipefd[1], 2);  // send stderr to the pipe

        close(pipefd[1]);    // this descriptor is no longer needed

        exec(...);
    }
}

// parent

char buffer[1024];

close(pipefd[1]);  // close the write end of the pipe in the parent

while (read(pipefd[0], buffer, sizeof(buffer)) != 0)
{
}

警告:输出将混合。如果您希望所有进程在不混合的情况下转储数据,那么您应该设法同步进程(例如,通过公共锁)。

【讨论】:

  • 我认为您可以在文件系统的任何位置(如本地套接字)创建命名通道并将所有接收到的数据读取到父进程。因此子进程必须将它们获取的数据写入此通道。它将是类 Unix 架构。
  • 好吧,如果我们有pipe 机制,我认为这是不必要的。您的解决方案无法解决混合数据的问题,因为对本地套接字的写入操作可能会被操作系统分散在多个事务中。我错了吗?
  • 可以传入发送数据的子进程的id。而且源代码会更简单。
  • 我试过了,但它不起作用。它只打印一些进程的输出。我在 execl() 中使用了 echo "test",并使用 printf("%s\n",buffer) 打印了缓冲区。结果我从来没有得到 10 个“测试”,只有 2 个或 3 个。
【解决方案3】:

我认为您可以在文件系统的任何位置(如本地套接字)创建命名通道并将所有接收到的数据读取到父进程。所以子进程必须将他们获得的数据写入这个通道。它将是类 Unix 架构。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多