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

How do I get n processes to wait using 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;
    }
}

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

根据您使用的 System-V 风格的信号量,一般方案最好是这样的:

  1. parent进程通过semget()创建或打开信号量,并通过semctl().

    [=35将其值初始化为0 =]
  2. parent分叉所有children.

  3. 每个child通过semop()对信号量执行decrement-by-one操作。例如,

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

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

  4. parent 使用 semop() 将信号量的值增加 child 个进程数。此信号量操作不阻塞,完成后,所有children都可以进行。

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

还有其他信号量操作组合可以实现您所描述的(以及更现代的信号量风格,您可以使用它们来执行其中的一些操作),但我敢说以上内容提供了标准 System-V 习语这样的任务。