信号量阻塞 children

Semaphore blocking children

我有一个问题,我想做一个 fork,例如一个 20 个进程的 fork,这个 fork 创建了,在最后一个没有创建之前不应该做任何事情,我想用信号量来做,如何我可以实现吗?

for (i=0; i<20; i++) {
   switch (fork()) {
       case: -1:
        exit(EXIT_FAILURE);

        case 0:
            execve(....); 
            exit(EXIT_FAILURE);

        default: 
            printf ("Child Created!");
   }

}

这是你的作业。你可以稍后付钱给我。

#include <semaphore.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
    sem_t *sem;
    if(MAP_FAILED==(sem=mmap(0, sizeof(*sem), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0)))
        { perror("mmap"); exit(EXIT_FAILURE); }

    if(0>sem_init(sem, 1/*shared*/, 0/*init val*/))
        { perror("sem_init"); exit(EXIT_FAILURE); }

    for(int i=0; i<20; i++){
        switch(fork()){
        case -1: perror("fork"); /*you'll need to kill the children here*/ 
                   exit(EXIT_FAILURE);
        case 0: 
                 puts("waiting");
                 sem_wait(sem);
                 puts("running");
                 exit(0);
        default:
                 puts("Child created"); 
        }
    }
    puts("done forking. signalling children");
    usleep(1000000);
    for(int i=0; i<20; i++)
        sem_post(sem);

}

这个想法很简单。将(必要的,共享的)信号量初始化为零,并让每个 child 在它做它的事情之前等待它。 当你在 parent 中完成分叉后,你 post 到信号量 20 次,以便每个 child 的 sem_wait 调用完成。

与 SysV 信号量相同:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

//the manpage says we should define this union (as follows)
union semun {
           int              val;    /* Value for SETVAL */
           struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
           unsigned short  *array;  /* Array for GETALL, SETALL */
           struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                       (Linux-specific) */
       };

int main()
{
    key_t key;
    char tmpl[]="/tmp/XXXXXX";
    {
        int tmpfd; 
        if(0>(tmpfd = mkstemp(tmpl)))
            { perror("mkstemp"); exit(EXIT_FAILURE); }
        close(tmpfd);
    }

    //Get a key
    puts(tmpl);
    key=ftok(tmpl, 'A');

    int sem;
    int ec = EXIT_SUCCESS;

    if(0>(sem = semget(key, 1 /*1 sem*/, IPC_CREAT|IPC_EXCL|0600)))
        { perror("semget"); goto fail; }
    if(0>semctl(sem, 0 /*ix*/, SETVAL, (union semun){ .val=0 }))
        { perror("sem init"); goto fail; }

    for(int i=0; i<20; i++){
        switch(fork()){
        case -1: { perror("fork"); /*you'll need to kill the children here*/ exit(EXIT_FAILURE);  }
        case 0: 
                 puts("waiting");
                 semop(sem, (struct sembuf[1]){{ .sem_op=-1  }}, 1);
                 puts("running");
                 exit(0);
        default:
                 puts("Child created"); 
        }
    }
    puts("done forking. signalling children");
    usleep(1000000);
    //can up it by 20 in one go
    semop(sem, (struct sembuf[1]){{ .sem_op=+20  }}, 1);
    goto success;

fail:  ec = EXIT_FAILURE;
success:
    semctl(sem, 0, IPC_RMID);
    unlink(tmpl);
    exit(ec);
}

在这里你必须绕过 SysV IPC API 丑陋和需要设置一个 file-based 密钥,但是作为奖励,你可以将信号量增加 20一口气