Synchronizing two child processes with semaphores in c
Asked Answered
U

1

6

I have to create a program that synchronizes two processes each printing only a single letter so that whenever we observe the output of the program, the difference between the amount of "A" and "B" is no greater than 2.

So this would be accepted:

BAABBAABBABA

this wouldn't be because it prints 4 B's and only 2 A's:

ABBABB

So for starters i decided to use the POSIX semaphores. I created two semaphores , giving them all the permissions using the sem_open Then i created two child processes and for each child process i open the semaphores i created as described in the man page for sem_open and manipulate them.

I don't think it's the logic of the sem_post and sem_wait that's at fault here, since the program seems to ignore them.

So my question is. What goes wrong?

Edit: I don't really need the solution to the problem. Some guidance alone would be much appreciated and welcoming as an answer. Thank you in advance!

#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <semaphore.h>

int main(void){



  sem_t *semA = sem_open("/semA", O_CREAT|O_EXCL, S_IRWXU | S_IRWXG | S_IRWXO, 0);   //Initialize semaphore(= 0) for process A
  sem_t *semB = sem_open("/semB", O_CREAT|O_EXCL, S_IRWXU | S_IRWXG | S_IRWXO, 0);   //Initialize semaphore(= 0) for process B


  if (fork()){      // parent process
    if(fork()){}
    else{
      sem_t *childsemA = sem_open("/semA", 0);
      sem_t *childsemB = sem_open("/semB", 0);
      while(1){
        printf("A");
        sem_post(childsemB);
        sem_wait(childsemA);
      }
    }
  }
  else{
    sem_t *childsemA = sem_open("/semA", 0);
    sem_t *childsemB = sem_open("/semB", 0);
    while(1){
      printf("B");    // child2 process
      sem_post(childsemA);
      sem_wait(childsemB);
    }
  }

  return 0;
}

Output:

enter image description here

Uund answered 10/1, 2019 at 20:47 Comment(7)
If I am not wrong, semaphore are intended to be used with thread ( lightweight processes ), not with processes. Fork create a process that does not share parent's memory, so I don't think your parent's semaphore has interaction with your child's semaphore.Pinkiepinkish
@mmeisson: No, OP is using sem_open() to open named semaphores; these are shared between processes.Secunderabad
OP, the standard C library buffers standard output. Add fflush(stdout); after each printf() to have the C library emit the letters to the actual standard output.Secunderabad
You don't need childsemA and childsemB, just use the semA and semB that was opened by the parent.Moorfowl
For strugglers, not to bog down your system, use wait(0); calls in parentsGardening
@NominalAnimal It seems that fflush was indeed the whole issue. Can't believe it was actually that simple. Thank you, i very much appreciate your help :)Uund
If problem is about count of A or B, semaphores on printf will not help but should be on count of printfs.Judah
W
2

May i suggest you to use System V semaphores? This is the code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/sem.h>

#include "Semaphores.h"

#define SEM1_KEY (key_t)888
#define SEM2_KEY (key_t)1234

int sem1, sem2;


int main()
{
    pid_t pid;

    sem1 = semget(SEM1_KEY, 1, IPC_CREAT | 0666);
    if(sem1 < 0)
    {
        fprintf(stderr, "\nSEMGET Failed\n");
        exit(EXIT_FAILURE);
    }

    sem2 = semget(SEM2_KEY, 1, IPC_CREAT | 0666);
    if(sem1 < 0)
    {
        fprintf(stderr, "\nSEMGET Failed\n");
        exit(EXIT_FAILURE);
    }

    SEM_SET(sem1, 1);
    SEM_SET(sem2, 0);

    if((pid = fork()) == -1)
    {
        fprintf(stderr, "\nError in fork()\n");
        exit(EXIT_FAILURE);
    }
    if(pid == 0)
    {
        while(1)
        {   
            SEM_WAIT(sem2);
            printf("%c", 'B');
            fflush(stdout);
            sleep(1);
            SEM_POST(sem1);
        }
    }

    while(1)
    {
        SEM_WAIT(sem1);
        printf("%c", 'A');
        fflush(stdout);
        sleep(1);
        SEM_POST(sem2);
    }

    wait(0);

    SEM_DEL(sem1);
    SEM_DEL(sem2);
    exit(EXIT_SUCCESS);
}

And this is the header file Semaphores.h which includes the System V semaphores implementation:

#include <sys/sem.h>


union semun
{
    int val;

    struct semid_ds * buf;

    unsigned short * array;

};


int SEM_SET(int sem_id, int sem_val)
{
    union semun sem_union;

    sem_union.val = sem_val;

    return semctl(sem_id, 0, SETVAL, sem_union);
}

int SEM_DEL(int sem_id)
{
    return semctl(sem_id, 0, IPC_RMID);
}

int SEM_WAIT(int sem_id)
{
    struct sembuf sem_buf;

    sem_buf.sem_num = 0;
    sem_buf.sem_op = -1;
    sem_buf.sem_flg = SEM_UNDO;
    return semop(sem_id, &sem_buf, 1);
}

int SEM_POST(int sem_id)
{
    struct sembuf sem_buf;

    sem_buf.sem_num = 0;
    sem_buf.sem_op = 1;
    sem_buf.sem_flg = SEM_UNDO;
    return semop(sem_id, &sem_buf, 1);
}

The result will be this:

ABABABABABABABABA and so on

fflush() was probably the problem, but your code has some leaks, you need to understand what is a critical section, and you need to check for the return values of fork().

Werra answered 14/2, 2019 at 18:24 Comment(1)
I'm upvoting this because it is a good answer, but it doesn't completely solve my original problem. You're forcing A and B to switch back and forth, while i'd like the code to allow a letter to appear twice in a row based on race conditions.Uund

© 2022 - 2024 — McMap. All rights reserved.