信号量阻止儿童 [英] Semaphore blocking children

查看:104
本文介绍了信号量阻止儿童的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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!");
   }

}

推荐答案

这是您的作业.您可以稍后再付款.

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

}

这个想法很简单.将(必要时,共享的)信号量初始化为零,并让每个孩子在做它的事情之前先等待它. 完成父项的分叉操作后,您将其张贴到信号量中20次,以便每个孩子的sem_wait调用完成.

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.

与SysV信号灯相同:

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

在这里,您必须绕过SysV IPC API的丑陋以及需要设置基于文件的密钥,但是作为奖励,您可以一次性将信号量增加20.

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.

这篇关于信号量阻止儿童的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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