阻止儿童的信号量

时间:2017-12-01 13:59:09

标签: c fork execv

我有一个问题,我想做一个fork例如一个20processes的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!");
   }

}

1 个答案:

答案 0 :(得分:3)

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

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

}

这个想法很简单。将(必然的,共享的)信号量初始化为零,并使每个孩子在它做它之前等待它。 当您在父母中完成分叉时,您会向信号量发送20次,以便每个孩子的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丑陋和设置基于文件的密钥的需要跳舞,但是,作为奖励,你可以一次性将信号量增加20倍。