从兄弟进程获取pid
Get pid from brother process
我想要一个父进程和三个子进程。我希望这些子进程知道其他子进程的 pids。
问题是,当我执行 fork 然后再次执行时,第二个 fork 也在子进程中执行,创建一个额外的进程(或者我认为)。
我该如何解决?
谢谢。
parent分叉三次,child人不分叉。这样,parent 将知道所有三个 children.
的 pids
分叉后,您将需要某种单独的通信渠道,parent 可以通过该渠道将这些 pids 传达给所有 children。一个简单的方法是在分叉每个 child 之前打开一个管道(参见 pipe(2)
),因此 child 继承管道的文件描述符(至少是读取端)和 parent 保持写结束。然后让 parent 将三个 pid 发送到每个管道并关闭它。
示例代码(很长,但这就是 C 的本质):
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define NUM_CHILDREN 3
/* Entry point for the child processes */
int child_main(int pipe_read_end) {
pid_t my_pid = getpid();
/* Read child pids from pipe */
int child_pids[NUM_CHILDREN];
unsigned int bytes_read = 0;
while (bytes_read < sizeof(child_pids)) {
ssize_t result = read(pipe_read_end, ((unsigned char *) child_pids) + bytes_read, sizeof(child_pids) - bytes_read);
if (result < 0) {
perror("error reading from pipe");
return 1;
} else if (result == 0) {
fprintf(stderr, "unexpected end of file\n");
return 1;
} else {
bytes_read += result;
}
}
close(pipe_read_end);
/* Do something useful with these child pids */
for (int i = 0; i < NUM_CHILDREN; i++) {
printf("Child %d received sibling pid %d\n", my_pid, child_pids[i]);
}
return 0;
}
/* Entry point for the parent process. */
int main() {
int child_pids[NUM_CHILDREN];
int pipe_write_ends[NUM_CHILDREN];
for (int i = 0; i < NUM_CHILDREN; i++) {
/* Create the pipe for child i */
int pipefd[2];
if (pipe(pipefd)) {
perror("error creating pipe");
return 1;
}
int pipe_read_end = pipefd[0];
int pipe_write_end = pipefd[1];
/* Fork child i */
pid_t child_pid = fork();
if (child_pid < 0) {
perror("error forking");
return 1;
} else if (child_pid == 0) {
printf("Child %d was forked\n", getpid());
close(pipe_write_end);
return child_main(pipe_read_end);
} else {
printf("Parent forked child %d\n", child_pid);
close(pipe_read_end);
pipe_write_ends[i] = pipe_write_end;
child_pids[i] = child_pid;
}
}
/* Send pids down the pipes for each child */
for (int i = 0; i < NUM_CHILDREN; i++) {
unsigned int bytes_written = 0;
while (bytes_written < sizeof(child_pids)) {
ssize_t result = write(pipe_write_ends[i], ((unsigned char *) child_pids) + bytes_written, sizeof(child_pids) - bytes_written);
if (result < 0) {
perror("error writing to pipe");
return 1;
} else {
bytes_written += result;
}
}
close(pipe_write_ends[i]);
}
/* Wait for children to exit */
for (int i = 0; i < NUM_CHILDREN; i++) {
if (waitpid(child_pids[i], 0, 0) < 0) {
perror("error waiting for child");
return 1;
}
}
}
正如@PSkocik 在 中指出的那样,您可能不应该这样做。 Pid 可以被 OS 重用,所以 children 无法知道他们的兄弟 pid 实际上仍然引用他们的兄弟;只有 parent 可以确定,因为它必须 wait
每个 pid 才能被重用。
然而,同样的机制可以用于其他形式的 IPC(inter-process 通信);例如,您可以使用它直接在 children 之间创建管道。
您可以使用共享内存或某种其他类型的 IPC 来传递 PID,但您可能甚至不应该尝试。
PID 会被回收,您只能确定 PID 是否指代您认为它指代的进程是否属于您的 child 进程(因为这样您就可以知道如果您 wait
是否使用过它)。
否则,PID(non-children)是活泼的引用,基本上只能用于 hacky 调试。
我想要一个父进程和三个子进程。我希望这些子进程知道其他子进程的 pids。 问题是,当我执行 fork 然后再次执行时,第二个 fork 也在子进程中执行,创建一个额外的进程(或者我认为)。 我该如何解决?
谢谢。
parent分叉三次,child人不分叉。这样,parent 将知道所有三个 children.
的 pids分叉后,您将需要某种单独的通信渠道,parent 可以通过该渠道将这些 pids 传达给所有 children。一个简单的方法是在分叉每个 child 之前打开一个管道(参见 pipe(2)
),因此 child 继承管道的文件描述符(至少是读取端)和 parent 保持写结束。然后让 parent 将三个 pid 发送到每个管道并关闭它。
示例代码(很长,但这就是 C 的本质):
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define NUM_CHILDREN 3
/* Entry point for the child processes */
int child_main(int pipe_read_end) {
pid_t my_pid = getpid();
/* Read child pids from pipe */
int child_pids[NUM_CHILDREN];
unsigned int bytes_read = 0;
while (bytes_read < sizeof(child_pids)) {
ssize_t result = read(pipe_read_end, ((unsigned char *) child_pids) + bytes_read, sizeof(child_pids) - bytes_read);
if (result < 0) {
perror("error reading from pipe");
return 1;
} else if (result == 0) {
fprintf(stderr, "unexpected end of file\n");
return 1;
} else {
bytes_read += result;
}
}
close(pipe_read_end);
/* Do something useful with these child pids */
for (int i = 0; i < NUM_CHILDREN; i++) {
printf("Child %d received sibling pid %d\n", my_pid, child_pids[i]);
}
return 0;
}
/* Entry point for the parent process. */
int main() {
int child_pids[NUM_CHILDREN];
int pipe_write_ends[NUM_CHILDREN];
for (int i = 0; i < NUM_CHILDREN; i++) {
/* Create the pipe for child i */
int pipefd[2];
if (pipe(pipefd)) {
perror("error creating pipe");
return 1;
}
int pipe_read_end = pipefd[0];
int pipe_write_end = pipefd[1];
/* Fork child i */
pid_t child_pid = fork();
if (child_pid < 0) {
perror("error forking");
return 1;
} else if (child_pid == 0) {
printf("Child %d was forked\n", getpid());
close(pipe_write_end);
return child_main(pipe_read_end);
} else {
printf("Parent forked child %d\n", child_pid);
close(pipe_read_end);
pipe_write_ends[i] = pipe_write_end;
child_pids[i] = child_pid;
}
}
/* Send pids down the pipes for each child */
for (int i = 0; i < NUM_CHILDREN; i++) {
unsigned int bytes_written = 0;
while (bytes_written < sizeof(child_pids)) {
ssize_t result = write(pipe_write_ends[i], ((unsigned char *) child_pids) + bytes_written, sizeof(child_pids) - bytes_written);
if (result < 0) {
perror("error writing to pipe");
return 1;
} else {
bytes_written += result;
}
}
close(pipe_write_ends[i]);
}
/* Wait for children to exit */
for (int i = 0; i < NUM_CHILDREN; i++) {
if (waitpid(child_pids[i], 0, 0) < 0) {
perror("error waiting for child");
return 1;
}
}
}
正如@PSkocik 在 wait
每个 pid 才能被重用。
然而,同样的机制可以用于其他形式的 IPC(inter-process 通信);例如,您可以使用它直接在 children 之间创建管道。
您可以使用共享内存或某种其他类型的 IPC 来传递 PID,但您可能甚至不应该尝试。
PID 会被回收,您只能确定 PID 是否指代您认为它指代的进程是否属于您的 child 进程(因为这样您就可以知道如果您 wait
是否使用过它)。
否则,PID(non-children)是活泼的引用,基本上只能用于 hacky 调试。