我正在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};
我是对的吗?
答案 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
,以便内核能够清理该进程。