fork 后同步 N 个兄弟进程 [英] Synchronising N sibling processes after fork

查看:15
本文介绍了fork 后同步 N 个兄弟进程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很难同步 N 个子进程,等待它们中的每一个到达某个特定点.我已经尝试过信号量和信号,但我无法理解它.

I'm having some hard time with synchronising N child process waiting each one of them to arrive at some specific point. I've tried semaphores and signals but I can't get my head around it.

#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
", 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
");
                exit(0);
            break;
            default:
                /* unleashing the kids when everyone is ready */
                wait(NULL);
                fprintf(stderr, "OK
");

            break;
        }
    }
    return 0;
}

void handle(int signum) {;}

而且我相信输出应该是(一旦孩子同步)

And I believe that the output should be (once the child are sync)

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

推荐答案

同步

有一个简单的技巧:

Synchronization

There's a simple trick:

  • 在你 fork 之前创建一个管道.
  • 让孩子各自关闭管道的写入端.
  • 让孩子在您想要同步时从管道中读取.
  • 在应该启动子级时让父级关闭管道的两端.
  • 让孩子在释放时关闭管道的读取端,以便释放资源.
  • 孩子们现在做他们的事"(长大、产出、死亡).
  • 父进程现在等待其子进程死亡(当您在 Unix 上玩进程时,这是一个病态的事情).

如果操作正确,子进程会同时获得 EOF(读取零字节),因为不再有任何进程可以写入管道.(这就是为什么在进行同步 read() 之前,让孩子关闭管道的写端很重要.)

If done correctly, the children all get EOF (zero bytes read) at the same time because there's no longer any process that can write to the pipe. (That's why it is important for the children to close the write end of the pipe before doing the synchronizing read().)

如果您希望父级知道子级已准备就绪,请在分叉之前创建两个管道.父进程关闭第二个管道的写端,然后从读端读取.在进入第一个管道上的 read() 调用之前,孩子们都关闭了管道的两端.当所有子进程都关闭了管道的写入端时,父进程将获得 EOF,因此它知道子进程已经全部启动,至少在关闭第二个管道时是这样.然后父级可以关闭第一个管道以释放子级(并关闭第二个管道的读取端).

If you want the parent to know that the children are all ready, create two pipes before forking anything. The parent process closes the write end of this second pipe, and then reads from the read end. The children all close both ends of the pipe before settling into their read() call on the first pipe. The parent process gets EOF when all the children have closed the write end of the pipe, so it knows the children have all started, at least as far as closing the second pipe. The parent can then close the first pipe to release the children (and close the read end of the second pipe).

您在开关的 default 子句中等待,这是不正确的.在进行任何等待之前,您需要启动所有四个子进程——否则它们将永远无法同步.当您等待时,您需要在(新)循环中进行等待.而且,在调试时,您应该添加打印语句来识别父进程中正在发生的事情.例如,您将打印退出进程的状态及其 PID:

You are waiting in the default clause of the switch, which is not correct. You need all four child processes launched before you do any waiting — otherwise they'll never all be able to synchronize. When you do wait, you'll need to do your waiting in a (new) loop. And, while debugging, you should add print statements to identify what is going on in the parent process. For example, you'll print the status of the processes that exit, and their PID:

int corpse;
int status;
while ((corpse = wait(&status)) > 0)
    printf("%d: child %d exited with status 0x%.4X
", (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
");
        return 1;
    }

    for (int i = 0; i < NUM_KIDS; i++)
    {
        switch (fork())
        {
        case 0:
            fprintf(stderr, "ready %d from %d
", (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
");
            return NUM_KIDS + i;
        case -1:
            fprintf(stderr, "failed to fork child %d
", i+1);
            return 1;
        default:
            break;
        }
    }

    close(p_pipe[1]);
    read(p_pipe[0], &c, 1);
    printf("%d: %d children started
", (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
", (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

这篇关于fork 后同步 N 个兄弟进程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆