我会使用未命名的pipe()。请记住:在 UNIX 中,在两个进程中 fork() 和 execve() 之后,文件描述符保持打开状态!所以你可以使用pipe()获取一对文件描述符,然后使用bash的echo >&FD写入fd,其中FD是文件描述符编号。
这非常直接、简单,并且使用的资源比我想象的任何其他东西都要少。使用select() 没问题,只是不要阻止read() 是我在我的示例中所做的,但select() 是pfds[0]。
示例程序(生成 10 个 bash 进程,它们发送“你好工作,我的 pid:XXX”,在生成进程之间等待 1 秒。示例只为所有子进程使用一个管道。我这样更改它是因为作者询问了在实践中,我会不推荐它(请参阅示例下方的注释)):
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
int main(int argc, char **argv) {
int pfds[2];
pid_t p;
assert(0 == pipe(pfds));
p = fork();
if (p == 0) {
unsigned int i;
char str_fd[3]; char *env[] = {NULL};
char *args[] = { "/bin/bash", "-c", "echo >&$1 hello world, my pid: $$"
, "-s", str_fd, NULL};
snprintf(str_fd, 3, "%d", pfds[1]);
str_fd[2] = 0;
for (i = 0; i < 10; i++) {
p = fork();
if(0 == p) {
assert(0 ==
execve( "/bin/bash", (char *const*)args
, (char *const*)env));
} else if (0 > p) {
perror("fork");
exit(1);
} else {
wait(NULL);
}
sleep(1);
}
} else if(p > 0) {
char *buf = malloc(100);
ssize_t sz;
printf("fd is %d, <hit Ctrl+C to exit>\n", pfds[1]);
while(0 < ( sz = read(pfds[0], buf, 100))) {
buf[99] = 0;
printf("received: '%s'\n", buf);
}
free(buf);
if (0 == sz) {
fprintf(stderr, "EOF!");
} else {
perror("read from bash failed");
}
wait(NULL);
} else {
perror("fork failed");
exit(1);
}
return 0;
}
示例程序输出:
$ gcc test.c && ./a.out
fd is 4, <hit Ctrl+C to exit>
received: 'hello world, my pid: 779
'
received: 'hello world, my pid: 780
'
received: 'hello world, my pid: 781
'
received: 'hello world, my pid: 782
'
received: 'hello world, my pid: 783
'
received: 'hello world, my pid: 784
'
received: 'hello world, my pid: 785
'
received: 'hello world, my pid: 786
'
received: 'hello world, my pid: 787
'
received: 'hello world, my pid: 788
'
工作,bashs 发送 'hello world, my pid: XXX\n' 到父进程都使用一个管道:-)。
尽管如此,这似乎可以像演示程序显示的那样工作(使用 POSIX 语义并在 Linux 和 MacOS X 下测试应该没问题),我建议每个子进程使用一个 pipe()。这将导致更少的问题,并且一次运行多个子进程也是可能的。 select() 或 epoll()(如果您有许多子进程)是您的朋友。
由于pipe() 非常便宜,特别是与 bash! 相比,我绝对不会为多个孩子使用同一管道(就像我现在更新的示例一样)。