在OSX上创建子进程并将子进程的stdin和stdout重定向到父进程?

时间:2013-10-07 20:08:34

标签: c macos exec fork pipe

我正在OSX上的Xcode中开发一个C程序。

(父)程序必须启动一个新的(子)进程,该进程通过stdin接收其输入并将结果输出到stdout。所以父进程将数据写入子进程的stdin,父进程从子进程的stdout中读取结果。

在Windows上我使用CreateProcess来执行上述操作,但我不确定它是如何在C中的OSX上完成的。

我相信我应该使用exec来启动进程,但是我不知道如何重定向exec启动的可执行文件(子进程)的stdin和stdout。从阅读手册看,如果我使用exec,子进程看起来也会成为父进程。子进程和父进程必须并行运行,以便父进程可以在需要时对子进程进行写入和读取。

那里有一位OSX C专家可以给我一个简单的例子说明上面是怎么做的吗?

由于

修改

我想我明白了。但是如果子进程是一个无限的while循环,等待stdin上的输入,那么它就不会变成“僵尸”,对吧?

子进程基本上是这样做的:

1. Read data from stdin (i.e. blocked until data is received)
2. Process data
3. Write result to stdout
4. Goto 1

在我阅读你的帖子后,我找到了这个页面:

http://www.jukie.net/~bart/snippets/popenRWE/popenRWE.c.html

但是,我在启动.exe(子进程)时遇到问题

在终端中,我会像这样启动.exe:

./ myApp.exe someParam1 someParam2 someParam3

API如下所示:

popenRWE(int *rwepipe, const char *exe, const char *const argv[])

我猜第二个论点应该是:

 const char* exe = "./myApp.exe";

并且第三个参数应该是:

 char* p0 = "./myApp.exe";
 char* p1 = "someParam1";
 char* p2 = "someParam2";
 char* p3 = "someParam3";

 char** argv[4] = {p0, p1,p2,p3};

我是对的吗?

1 个答案:

答案 0 :(得分:3)

我包括我刚才写过的一个小型图书馆的来源。这应该让你开始。 fork / pipe / exec实际上并不那么容易(尤其是exec的所有变体)并且它花了我一段时间。所以这里:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include "limbo.h"

int out_pipe[2], err_pipe[2];

int run_command(char *argv[], int *out_length, int *err_length){
    pid_t pid;
    int status = 0;
    struct stat out_stat, err_stat;

    pipe(out_pipe); //create a pipe
    pipe(err_pipe);
    if(!(pid = fork())) //spawn child 
    {
        // Child. Close the read end of the pipe
        close(out_pipe[0]);
        close(err_pipe[0]);
        // redirect stdout and stderr to the write end of the pipe
        dup2(out_pipe[1], STDOUT_FILENO);
        dup2(err_pipe[1], STDERR_FILENO);
        status = execv(argv[0], argv); //child will terminate here
    }

    //Only parent gets here. Close write end of the pipe
    close(out_pipe[1]);
    close(err_pipe[1]);
    //or wait for the child process to terminate
    waitpid(pid, &status, 0);

    fstat(out_pipe[0], &out_stat);
    fstat(err_pipe[0], &err_stat);

    *out_length = (int) out_stat.st_size;
    *err_length = (int) err_stat.st_size;

    return status;
}

int read_buffers(char *out_buffer, int out_length, char *err_buffer, int err_length){
    out_buffer[read(out_pipe[0], out_buffer, out_length)] = 0;
    err_buffer[read(err_pipe[0], err_buffer, err_length)] = 0;

    return 0;
}

代码中的注释应该可以帮助您理解代码。随意重复使用。

修改

回应你的评论:

waitpid()调用使父进程等待子进程终止。如果您希望两个进程并行运行,则需要在我使用它的位置删除waitpid()但要小心:没有调用其中一个wait函数,一旦完成,您的子进程就会变成僵尸。您有责任密切关注您的子进程和wait,以便内核能够清理该进程。