John Smith
John Smith

Reputation: 53

Wait for a Forked Process when using a Semaphore

I'm trying to code an exercise in C Linux where I have one semaphore with 2 spots and "n" processes entered by argument. I need that the first 2 processes use the semaphore using the 2 spots for 5 secs each and then leave the semaphore for the other remaining processes to do their stuff. The problem is that not all the other processes wait for the semaphore to be free and some of them show a semaphore error (look at the results at the bottom). I believe the problem is on the waits for the child processes, because I have a waitipid and a wait function, but I need that if there's a free spot in the semaphore, any child process running could use it. Here's the code:

//gcc SemaphoreExample.c -o s
//./s 5

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/sem.h>

void semaphoreTask(int semid, int semnum, int semBusy)
{
    struct sembuf data;
    data.sem_num = semnum;
    data.sem_flg = 0;
    data.sem_op = semBusy;

    if(semop(semid,&data,1) == -1)
    {
        printf("\nSemaphore Error\n");
        exit(-1);
    }
}

int main(int argc, char *argv[])
{
    int i, fdSemaphore, quantity, fdsemctl, j;
    pid_t pid[15];

    system("clear");

    if(argc-1 < 1)
    {
        printf("Some arguments are missing\n");
        return EXIT_FAILURE;
    }

    printf("Number of arguments entered:\n\nargc: %d\n\nValues from the arguments:\n\n",argc-1);

    for(i=0;i<argc;i++)
    {
        printf("argv[%d]: %s\n",i,argv[i]);
    }

    printf("\n\n");

    fdSemaphore = semget(1234,1,IPC_CREAT|0777);

    if(fdSemaphore == -1)
    {
        printf("\nError creating the Semaphore\n");
        return EXIT_FAILURE;
    }

    fdsemctl = semctl(fdSemaphore,0,SETVAL,2);

    if(fdsemctl == -1)
    {
        printf("\nError opening the Semaphore\n");
        return EXIT_FAILURE;
    }

    quantity = atoi(argv[1]);

    for(i=0;i<quantity;i++)
    {
        pid[i] = fork();

        if(pid[i] == -1)
        {
            printf("\nError creating the Child Process\n");
            return EXIT_FAILURE;
        }

        if(pid[i] == 0)
        {
            semaphoreTask(fdSemaphore,0,-1);
            printf("\n[%d] I go to sleep\n",getpid());
            sleep(5);
            printf("\n[%d] I wake up\n",getpid());
            semaphoreTask(fdSemaphore,0,1);
        }
        else
        {
            //printf("\nJust wait\n");
            waitpid(pid[i],NULL,WNOHANG);
        }
    }

    for(j=0;j<quantity;j++)
    {
        wait(NULL);
    }

    semctl(fdSemaphore,0,IPC_RMID);

    return EXIT_SUCCESS;
}

This is the result I got:

Result:

Number of arguments entered:

argc: 1

Values from the arguments:

argv[0]: ./s
argv[1]: 5


[2845] I go to sleep

[2844] I go to sleep

[2845] I wake up

[2844] I wake up

Semaphore Error

[2843] I go to sleep

Semaphore Error

Semaphore Error

[2843] I wake up

Semaphore Error

Should I use wait or waitpid only?

Upvotes: 0

Views: 1199

Answers (2)

Arun Taylor
Arun Taylor

Reputation: 1572

The problem is semaphores are getting removed by forked children.

After line

semaphoreTask(fdSemaphore,0,1);

add

exit(0);

Upvotes: 1

Arun Taylor
Arun Taylor

Reputation: 1572

It is much simpler to implement what you want if you use sem_post and sem_wait calls. I am on a OpenBSD system and I am assuming that Linux has the same thing.

Upvotes: 0

Related Questions