man0s
man0s

Reputation: 189

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

Upvotes: 2

Views: 3776

Answers (1)

Jonathan Leffler
Jonathan Leffler

Reputation: 755064

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

Upvotes: 3

Related Questions