fork后同步N个兄弟进程
Synchronising N sibling processes after fork
我在同步 N 个 child 进程时遇到了一些困难,等待它们中的每一个都到达某个特定点。
我已经尝试过信号量和信号,但我无法理解它。
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <fcntl.h>
#include <semaphore.h>
#include <sys/wait.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/msg.h>
#define NUM_KIDS 4
void handle(int signum);
int main(int argc, char const *argv[])
{
sem_t* sem;
sem = sem_open("/ok", O_CREAT, 0);
signal(SIGUSR1, handle);
for(int i = 0; i < NUM_KIDS; i++) {
switch(fork()) {
case 0:
fprintf(stderr, "ready %d from %d\n", getpid(), getppid());
/* i would like that each child stop here untill everyone is ready */
for(int j = 0; j < 10; j++)
fprintf(stderr, "lot of stuff\n");
exit(0);
break;
default:
/* unleashing the kids when everyone is ready */
wait(NULL);
fprintf(stderr, "OK\n");
break;
}
}
return 0;
}
void handle(int signum) {;}
而且我认为输出应该是(一旦 child 同步)
ready ... from xxx
ready ... from xxx
ready ... from xxx
ready ... from xxx
...lots of stuff... 10 times
...lots of stuff... 10 times
...lots of stuff... 10 times
...lots of stuff... 10 times
同步
有一个简单的技巧:
- 在 fork 之前先创建一个管道。
- 让 children 分别关闭管道的写入端。
- 当你想同步它们时,让 children 从管道中读取它们。
- 当 children 应该启动时,让 parent 关闭管道的两端。
- 让 children 在释放时关闭管道的读取端,以便释放资源。
- child人现在做'their thing'(长大,产出,死亡)。
- parent 现在等待它的 children 死掉(当你在 Unix 上玩进程时,这是一件病态的事情)。
如果操作正确,children 将同时获得 EOF(读取零字节),因为不再有任何进程可以写入管道。 (这就是为什么 children 在进行同步 read()
之前关闭管道的写入端很重要。)
如果你想让 parent 知道 children 都准备好了,在分叉任何东西之前创建两个管道。 parent 进程关闭第二个管道的写入端,然后从读取端读取。 children 在进入第一个管道上的 read()
调用之前全部关闭管道的两端。 parent 进程在所有 children 关闭管道的写入端时获得 EOF,因此它知道 children 都已启动,至少就关闭第二个管道而言. parent 然后可以关闭第一个管道以释放 children(并关闭第二个管道的读取端)。
别等得太早!
您在开关的 default
子句中等待,这是不正确的。在进行任何等待之前,您需要启动所有四个 child 进程——否则它们将永远无法全部同步。当你等待时,你需要在一个(新的)循环中等待。并且,在调试时,您应该添加打印语句来识别 parent 进程中发生了什么。例如,您将打印退出进程的状态及其 PID:
int corpse;
int status;
while ((corpse = wait(&status)) > 0)
printf("%d: child %d exited with status 0x%.4X\n", (int)getpid(), corpse, status);
工作代码
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#define NUM_KIDS 4
int main(void)
{
int p_pipe[2];
int c_pipe[2];
char c;
if (pipe(p_pipe) != 0 || pipe(c_pipe) != 0)
{
fprintf(stderr, "Oops: failed to create pipes\n");
return 1;
}
for (int i = 0; i < NUM_KIDS; i++)
{
switch (fork())
{
case 0:
fprintf(stderr, "ready %d from %d\n", (int)getpid(), (int)getppid());
close(p_pipe[0]);
close(p_pipe[1]);
close(c_pipe[1]);
read(c_pipe[0], &c, 1);
close(c_pipe[0]);
for (int j = 0; j < 10; j++)
fprintf(stderr, "lot of stuff\n");
return NUM_KIDS + i;
case -1:
fprintf(stderr, "failed to fork child %d\n", i+1);
return 1;
default:
break;
}
}
close(p_pipe[1]);
read(p_pipe[0], &c, 1);
printf("%d: %d children started\n", (int)getpid(), NUM_KIDS);
close(c_pipe[0]);
close(c_pipe[1]);
int corpse;
int status;
while ((corpse = wait(&status)) >= 0)
printf("%d: child %d exited with status 0x%.4X\n", (int)getpid(), corpse, status);
return 0;
}
样本运行
ready 81949 from 81948
ready 81950 from 81948
ready 81951 from 81948
ready 81952 from 81948
81948: 4 children started
lot of stuff
lot of stuff
lot of stuff
lot of stuff
…lines omitted for brevity…
lot of stuff
lot of stuff
lot of stuff
lot of stuff
81948: child 81951 exited with status 0x0600
81948: child 81952 exited with status 0x0700
81948: child 81950 exited with status 0x0500
81948: child 81949 exited with status 0x0400
我在同步 N 个 child 进程时遇到了一些困难,等待它们中的每一个都到达某个特定点。 我已经尝试过信号量和信号,但我无法理解它。
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <fcntl.h>
#include <semaphore.h>
#include <sys/wait.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/msg.h>
#define NUM_KIDS 4
void handle(int signum);
int main(int argc, char const *argv[])
{
sem_t* sem;
sem = sem_open("/ok", O_CREAT, 0);
signal(SIGUSR1, handle);
for(int i = 0; i < NUM_KIDS; i++) {
switch(fork()) {
case 0:
fprintf(stderr, "ready %d from %d\n", getpid(), getppid());
/* i would like that each child stop here untill everyone is ready */
for(int j = 0; j < 10; j++)
fprintf(stderr, "lot of stuff\n");
exit(0);
break;
default:
/* unleashing the kids when everyone is ready */
wait(NULL);
fprintf(stderr, "OK\n");
break;
}
}
return 0;
}
void handle(int signum) {;}
而且我认为输出应该是(一旦 child 同步)
ready ... from xxx
ready ... from xxx
ready ... from xxx
ready ... from xxx
...lots of stuff... 10 times
...lots of stuff... 10 times
...lots of stuff... 10 times
...lots of stuff... 10 times
同步
有一个简单的技巧:
- 在 fork 之前先创建一个管道。
- 让 children 分别关闭管道的写入端。
- 当你想同步它们时,让 children 从管道中读取它们。
- 当 children 应该启动时,让 parent 关闭管道的两端。
- 让 children 在释放时关闭管道的读取端,以便释放资源。
- child人现在做'their thing'(长大,产出,死亡)。
- parent 现在等待它的 children 死掉(当你在 Unix 上玩进程时,这是一件病态的事情)。
如果操作正确,children 将同时获得 EOF(读取零字节),因为不再有任何进程可以写入管道。 (这就是为什么 children 在进行同步 read()
之前关闭管道的写入端很重要。)
如果你想让 parent 知道 children 都准备好了,在分叉任何东西之前创建两个管道。 parent 进程关闭第二个管道的写入端,然后从读取端读取。 children 在进入第一个管道上的 read()
调用之前全部关闭管道的两端。 parent 进程在所有 children 关闭管道的写入端时获得 EOF,因此它知道 children 都已启动,至少就关闭第二个管道而言. parent 然后可以关闭第一个管道以释放 children(并关闭第二个管道的读取端)。
别等得太早!
您在开关的 default
子句中等待,这是不正确的。在进行任何等待之前,您需要启动所有四个 child 进程——否则它们将永远无法全部同步。当你等待时,你需要在一个(新的)循环中等待。并且,在调试时,您应该添加打印语句来识别 parent 进程中发生了什么。例如,您将打印退出进程的状态及其 PID:
int corpse;
int status;
while ((corpse = wait(&status)) > 0)
printf("%d: child %d exited with status 0x%.4X\n", (int)getpid(), corpse, status);
工作代码
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#define NUM_KIDS 4
int main(void)
{
int p_pipe[2];
int c_pipe[2];
char c;
if (pipe(p_pipe) != 0 || pipe(c_pipe) != 0)
{
fprintf(stderr, "Oops: failed to create pipes\n");
return 1;
}
for (int i = 0; i < NUM_KIDS; i++)
{
switch (fork())
{
case 0:
fprintf(stderr, "ready %d from %d\n", (int)getpid(), (int)getppid());
close(p_pipe[0]);
close(p_pipe[1]);
close(c_pipe[1]);
read(c_pipe[0], &c, 1);
close(c_pipe[0]);
for (int j = 0; j < 10; j++)
fprintf(stderr, "lot of stuff\n");
return NUM_KIDS + i;
case -1:
fprintf(stderr, "failed to fork child %d\n", i+1);
return 1;
default:
break;
}
}
close(p_pipe[1]);
read(p_pipe[0], &c, 1);
printf("%d: %d children started\n", (int)getpid(), NUM_KIDS);
close(c_pipe[0]);
close(c_pipe[1]);
int corpse;
int status;
while ((corpse = wait(&status)) >= 0)
printf("%d: child %d exited with status 0x%.4X\n", (int)getpid(), corpse, status);
return 0;
}
样本运行
ready 81949 from 81948
ready 81950 from 81948
ready 81951 from 81948
ready 81952 from 81948
81948: 4 children started
lot of stuff
lot of stuff
lot of stuff
lot of stuff
…lines omitted for brevity…
lot of stuff
lot of stuff
lot of stuff
lot of stuff
81948: child 81951 exited with status 0x0600
81948: child 81952 exited with status 0x0700
81948: child 81950 exited with status 0x0500
81948: child 81949 exited with status 0x0400