1

我正在 OSX 上的 Xcode 中编写 C 程序。

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

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

我相信我应该使用 exec 来启动进程,但我看不到我如何重定向 exec 启动的可执行文件(子进程)的标准输入和标准输出。从阅读手册来看,如果我使用 exec,子进程似乎也将成为父进程。子进程和父进程必须并行运行,以便父进程可以在需要时对子进程进行读写。

那里有一位好心的 OSX C 专家可以给我一个简短的例子来说明上述是如何完成的吗?

谢谢

编辑

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

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

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};

我对吗?

4

1 回答 1

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它,以便内核可以清理该进程。

于 2013-10-07T20:17:30.657 回答