Search code examples
cforkwaitsemaphore

How do I get n processes to wait using semaphore?


I'd need some of your help again...

I'm trying to develop a Program in C which does the following:

managerProcess creates NUM_PROCESSES Student processes.

Each Student Process once it gets created, waits for other Student processes to be created until number of processes created.

When all Student Processes are created, they start to do their job, which is not relevant to this question.

Important thing: Each Student Process must have same code.

Here's some code I wrote:

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

At last main.c File:

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

As you may notice, code above creates NUM_PROCESSES Student Processes and that's good. What I want to do is that each Student Process waits for all NUM_PROCESSES Student Processes creation and only then they start doing other things. How can I achieve that using Semaphore developed below?

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

Hope I've been clear. Thank you very much


Solution

  • With the System-V flavor of semaphore that you're using, the general scheme would go best like this:

    1. The parent process creates or opens the semaphore via semget(), and initializes its value to 0 via semctl().

    2. The parent forks all the children.

    3. Each child performs a decrement-by-one operation on the semaphore via semop(). For example,

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

      Each child will block until it can perform this operation without making the semaphore's value negative.

    4. The parent uses semop() to increase the semaphore's value by the number of child processes. This semaphore operation does not block, and after it completes, all the children will be able to proceed.

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

    There are other combinations of semaphore operations that could achieve what you describe (and more modern flavors of semaphores with which you could perform some of them), but I daresay the above presents the standard System-V idiom for such a task.