我如何让n个进程等待使用信号量?

时间:2019-01-05 17:10:35

标签: c fork wait semaphore

我将再次需要您的帮助...

我正在尝试用C语言开发一个程序,该程序可以执行以下操作:

managerProcess创建NUM_PROCESSES Student进程。

每个Student进程一旦创建,就等待其他Student进程被创建,直到创建的进程数为止。

创建所有Student流程后,它们开始做自己的工作,这与该问题无关。

重要的事情:每个Student进程必须具有相同的代码。

这是我写的一些代码:

pid_t run_child(Student s, int index, int (*function)(Student s, int index)){
    pid_t  p;
    p = fork();
    if (p == -1) 
        return -1;
    else if (!p)
        exit(function(s, index));
    else 
        return p;
}



int child_process(Student s, int index){
    //This printf is executed NUM_PROCESSES times 
    printf("Child Process %d has been created\n", getpid());
    //Once reached this point each Process running this function will do other things

    /*SOME OTHER CODE STUDENT PROCESSES EXECUTE*/
    printf("%d Student Processes Created\n", NUM_PROCESSES);
    return EXIT_SUCCESS;
}

最后main.c个文件:

int main(int argc, char *argv[]){
    pid_t  child_pid[NUM_PROCESSES];
    int    child_status[NUM_PROCESSES];
    int i;
    int status;
    status = EXIT_SUCCESS; 

    for (i = 0; i < NUM_PROCESSES; i++) {
        Student s;
        child_pid[i] = run_child(s, i, child_process);
        if (child_pid[i] == -1) {
            fprintf(stderr, "Cannot fork a child process: %s.\n", strerror(errno));
            status = EXIT_FAILURE;
        } 
    }
    return status;
}

您可能会注意到,上面的代码创建了NUM_PROCESSES Student流程,这很好。 我想做的是每个Student进程都等待所有NUM_PROCESSES Student进程的创建,然后它们才开始做其他事情。 如何使用下面开发的Semaphore实现这一目标?

//Creates ONE Semaphore
int createSemaphore(key_t semaphoreKey){
    int semaphoreId = semget(semaphoreKey, 1, 0666 | IPC_CREAT);
    if(semaphoreId == -1){
        printf(RED "Semaphore Creation failed\n"RESET);
        return -1;
    }
    return semaphoreId;
}

//Creates a set of Semaphores with numSems Semaphores
int createSemaphoreSet(key_t semaphoreKey, int numSems){
    int semaphoreId = semget(semaphoreKey, numSems, 0666 | IPC_CREAT);
    if(semaphoreId == -1){
        printf(RED "Semaphore Set Creation Failed\n" RESET);
        return -1;
    }
    return semaphoreId;
}

//Decreases semaphores value by 1
void semaphoreWait(int semaphoreId, int semaphoreNumber){
    struct sembuf buffer;
    buffer.sem_num = semaphoreNumber;
    buffer.sem_op = -1;
    buffer.sem_flg = 0;
    int done = semop(semaphoreId, &buffer, 1);
    if(done == -1){
        printf(RED "Wait on Semaphore %d failed\n" RESET, semaphoreNumber);
        return;
    }
}

//Increments semaphore's value by 1
void semaphoreSignal(int semaphoreId, int semaphoreNumber){
    struct sembuf buffer;
    buffer.sem_num = semaphoreNumber;
    buffer.sem_op = 1;
    buffer.sem_flg = 0;
    int done = semop(semaphoreId, &buffer, 1);
    if(done == -1){
        printf(RED "semaphoreSignal Failed on Semaphore %d\n" RESET, semaphoreNumber);
        return;
    }
}

希望我已经清楚了。 非常感谢

1 个答案:

答案 0 :(得分:1)

有了您使用的System-V信号量,一般方案将最好地像这样:

  1. 父进程通过semget()创建或打开信号量,并通过semctl()将其值初始化为0。

  2. 父母分叉了所有孩子。

  3. 每个孩子都通过semop()对信号量执行一次递减运算。例如,

    struct sembuf semops = { .sem_num = 0, .sem_op = -1 };
    int result = semop(semid, &semops, 1);
    

    每个孩子都会阻塞,直到可以执行此操作而不会使信号量的值为负。

  4. 父级使用semop()通过子进程数来增加信号量的值。此信号量操作不会阻止,完成后,所有孩子都可以继续进行。

    struct sembuf semops2 = { .sem_num = 0, .sem_op = NUM_PROCESSES };
    int result2 = semop(semid, &semops2, 1);
    

还有信号灯操作的其他组合可以实现您描述的内容(以及可以用来执行其中一些信号的更现代的信号灯样式),但是我敢说以上内容为此类任务提供了标准的System-V习惯用法。