Semaphore blocking children

霸气de小男生 提交于 2019-12-11 05:51:51

问题


I have a problem, I would like to do a fork for example a fork of 20processes, this fork created, should not do anything until the last one is not created, and I want to do it with semaphore, how can I implement it?

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

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

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

}


回答1:


Here's you homework. You can pay me later.

#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);

}

The idea is simple. Init the (necessarily, shared) semaphore to zero and make each child wait on it before it does its thing. When you're done forking in the parent, you post to the semaphore 20 times so that each child's sem_wait call completes.

Same thing with with SysV semaphores:

#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);
}

Here you have to dance around the SysV IPC API ugliness and the need to set up an file-based key, but then, as a reward, you get to increment the semaphore by 20 in one go.



来源:https://stackoverflow.com/questions/47595022/semaphore-blocking-children

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!