我正在 OSX 上的 Xcode 中开发 C 程序。
(父)程序必须启动一个新的(子)进程,该进程通过标准输入接收输入并将结果输出到标准输出。所以父进程将数据写入子进程的标准输入,父进程从子进程的标准输出读取结果。
在 Windows 上,我使用 CreateProcess 执行上述操作,但我不确定在 C 中的 OSX 上是如何完成的。
我相信我应该使用 exec 来启动进程,但我看不到如何重定向 exec 启动的可执行文件(子进程)的标准输入和标准输出。从阅读手册来看,如果我使用 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};
我说得对吗?
最佳答案
我包含了我不久前编写的一个小型库的源代码。那应该让你开始。 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
函数,您的子进程将在完成后变成僵尸进程。您有责任关注您的子进程并等待
,以便内核清理该进程。
关于在 OSX 上创建子进程并将子进程的标准输入和标准输出重定向到父进程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19233767/