Я бы сделал это с неназванным pipe()
. Помните: в UNIX файловые дескрипторы остаются открытыми после fork()
и execve()
в обоих процессах! Таким образом, вы можете использовать pipe()
, чтобы получить пару файловых дескрипторов, а затем записать в fd, используя bash's echo >&FD
, где FD
- номер дескриптора файла.
Это очень просто, легко и использует меньше ресурсов, чем я полагаю. Использование select()
не проблема, просто не блокируйте на read()
, как я делаю в моем примере, но select()
на pfds[0]
.
Пример программы (порождает 10 процессов bash, которые отправляют 'hello work, my 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 !, я бы точно не использовал одну и ту же трубу для более чем одного ребенка (как сейчас делает мой обновленный образец).