Search code examples
cprocessposixsemaphore

POSIX semaphores between child and parent processes


Im trying to learn semaphores and how they work between processes, so i wanted to create a program that prints 10 times the string "abcd" from two separate for() loops. One for() contains the "ab" string while the other one contains the "cd" string. I thought the code was fine but apparently its not. I would appreciate if you could point out anything wrong or if i got something misunderstood.

Here's the code:

int main(void)
{

int i;
char *p;
sem_t *sem; //First semaphore
sem_t *sem2; //Second semaphore

//create, initialize semaphores
sem = sem_open("/semaphore1", O_CREAT,  0644, 1);
sem2 = sem_open("/semaphore2", O_CREAT,  0644, 1);

if (fork()) //Child process
{
     for (i=0;i<10;i++)
     {
        sem_wait(sem2); //Lock the semaphore
        for (p="ab"; *p; p++)
        {
            write(1, p, 1);
            usleep(100);
        }
        sem_post(sem); //Release the semaphore lock
     }
     wait(NULL);
}
else //Parent process
{
     for (i=0;i<10;i++)
     {
        sem_wait(sem); //Lock the semaphore
        for (p="cd\n"; *p; p++)
        {
            write(1, p, 1);
            usleep(100);
        }
        sem_post(sem2); //Release the semaphore lock
     }
}

//Close the Semaphores
sem_close(sem);
sem_unlink("/semaphore1");
sem_close(sem2);
sem_unlink("/semaphore2");
return 0;
}

And one of the outputs:

abcd
cadb
cadb
cadb
cabd
cabd
cabd
cadb
cabd
cadb

Solution

  • As noted in a comment, you need to initialize the first semaphore (renamed sem1 for symmetry with sem2 in the code below) to 0 instead of 1 so that the parent process gets to go first.

    The child and parent process comments were misplaced (the parent gets a non-zero result from fork() and so works in the if). This version produces the desired output even without any calls to usleep(). Nominally, only one of the processes needs to use sem_close() and sem_unlink(), but since you don't check for or report any errors, you don't notice the calls that fail.

    #include <stdio.h>
    #include <semaphore.h>
    #include <unistd.h>
    #include <sys/wait.h>
    
    int main(void)
    {
        int i;
        char *p;
        sem_t *sem1; // First semaphore
        sem_t *sem2; // Second semaphore
    
        // create, initialize semaphores
        sem1 = sem_open("/semaphore1", O_CREAT,  0644, 0);
        sem2 = sem_open("/semaphore2", O_CREAT,  0644, 1);
    
        if (fork()) // Parent process
        {
            for (i = 0; i < 10; i++)
            {
                sem_wait(sem2); // Lock the semaphore
                for (p = "ab"; *p; p++)
                {
                    write(1, p, 1);
                    //usleep(100);
                }
                sem_post(sem1); // Release the semaphore lock
            }
            wait(NULL);
        }
        else // Child process
        {
            for (i = 0; i < 10; i++)
            {
                sem_wait(sem1); // Lock the semaphore
                for (p = "cd\n"; *p; p++)
                {
                    write(1, p, 1);
                    //usleep(100);
                }
                sem_post(sem2); // Release the semaphore lock
            }
        }
    
        // Close the Semaphores
        sem_close(sem1);
        sem_unlink("/semaphore1");
        sem_close(sem2);
        sem_unlink("/semaphore2");
        return 0;
    }
    

    Example output:

    abcd
    abcd
    abcd
    abcd
    abcd
    abcd
    abcd
    abcd
    abcd
    abcd