2

I have 2 programs that need to communicate with each other, the first one must output what the second one puts into the shared memory, but I've removed everything but the semaphores, because there is a problem with synchronization. This is a school assignment, so I must use semaphores in exactly the way shown below, don't propse anything else because I can't use it.

#include <sys/shm.h>
#include <errno.h>
#include <sys/sem.h>

int main()
{
    int semid;
    struct sembuf sobs; 
    semid=semget(9999,1,IPC_CREAT|0600);
    semctl(semid, 0, SETVAL,1);
    sobs.sem_num=0;
    sobs.sem_op= 0;
    sobs.sem_flg=0;
    semop(semid,&sobs,1); 
/* DO SOMETHING */
    sobs.sem_op=1;
    semop(semid,&sobs,1);

shmctl(shmid1,IPC_RMID,0);
  return 0;
}

And the second program:

#include <sys/shm.h>
#include <errno.h>
#include <sys/sem.h>
int main()
{
  int semid;
  struct sembuf sobs; 
  semid=semget(9999,1,0600);

    sobs.sem_num=0;
    sobs.sem_op=-1;
    sobs.sem_flg=0;
    semop(semid,&sobs,1); 
     /* DO SOMETHING */
    sobs.sem_op=1;
    semop(semid,&sobs,1);
shmctl(shmid1,IPC_RMID,0);
  return 0;
}

So the problem is that if I put a sleep() above the DO SOMETHING in the second program, the first one will still go into the critical section, and it will finish before the second one, but the first one mustn't go into the critical section before the second one exits it, what can I do to prevent the first one from entering?

Maticb
  • 33
  • 4
  • Is it POSIX system? Can't see `sem_init`, `sem_wait` etc. – bytefire May 27 '14 at 09:53
  • I don't really know what POSIX is, but it's a Linux, I specifically use Backtrak 5. – Maticb May 27 '14 at 09:56
  • I see, you're using inter-process (IPC) semaphores. This may help: http://beej.us/guide/bgipc/output/html/multipage/semaphores.html. Also found this on Google http://www.cs.cf.ac.uk/Dave/C/node26.html – bytefire May 27 '14 at 10:02
  • That is quite a complex code there, I will look into it later when I get time but thanks. – Maticb May 27 '14 at 10:26
  • If I'm reading it correctly, the first program sets the semaphore to 1, and then waits for it to go to 0. The second program decrements the semaphore, which allows the first program to continue. Then both programs simultaneously execute the `do something` code, and finally both programs increment the semaphore (with no useful effect). What's missing here is a specification of what's supposed to happen, i.e. who's supposed to wait for whom, and why, and for how long. – user3386109 May 27 '14 at 10:32
  • Perhaps I didn't describe it good enough so I'll go again; The first program creates the semaphor and a char array of 20 (but that is working 100% because it was the same in the last assignment we had) Now we had to add a semaphore, that has to make the A program wait for B to insert some data into the char array, which is then simply printf() in the A program. – Maticb May 27 '14 at 10:41
  • Those are so-called SYSV (SystemV) semaphores as opposed to POSIX semaphores. If anyone is interested in the differences: http://stackoverflow.com/questions/368322/differences-between-system-v-and-posix-semaphores IIRC, the SYSV IPC was more common than POSIX IPC for quite some time. Don't think that's true any more, all systems I know support both. – DarkDust May 27 '14 at 11:33

2 Answers2

0

Typically program A should set the semaphore to 0 initially using semctl. Then program A calls semop with sobs.sem_op=-1, to wait on the semaphore.

Program B doesn't need to do anything with the semaphore before "do something". (Note that A has to be run first, so that the semaphore is created and setup before B starts.) After B is done it should signal A by calling semop with sobs.sem_op=1.

In short A sets up the semaphore and waits for it before "doing something". B "does something" and then signals the semaphore to wake A.

user3386109
  • 34,287
  • 7
  • 49
  • 68
  • Thanks, that did help, but I did it by first setting to 1, then waiting for 0 and -1 in b, it did not work the way you said (starting with 0), but perhaps I did something wrong. – Maticb May 27 '14 at 11:14
0

You're using so-called SysV (System V) semaphores, as opposed to POSIX semaphores. You might want to look up tutorials for that. Your first mistake is the first argument to semget: you aren't supposed to pass it a value that you've defined, you should use ftok(3) instead (if you chose the key yourself collisions are pretty likely: too many people will simply use 1 or 42 as key value).

Next, some explanations on how semaphores work:

  • A semaphore has a value.
  • You can increase its value (foo.sem_op > 0). This is a non-blocking operation.
  • You can decrease its value (foo.sem_op < 0). This may block (which is what it's used for). Explanation below.
  • You can wait for it to become 0 (foo.sem_op == 0). If the semaphore is already 0 it doesn't block, otherwise it blocks.

When you decrease the semaphore, the following scenarios can happen (simplified):

  • If decreasing the semaphore would not make it become negative the call does not block.
  • If decreasing the semaphore by the value in foo.sem_op would make the semaphore negative it will block until the semaphore's value has become large enough so that the decreasing won't make the semaphore negative any more.

You'd like to use the semaphore as a mutex. In this case you only want values of "1". The pattern now usually looks like this:

  • Initialize the semaphore, set it to 1.
  • The first worker decreases the semaphore by -1. This immediately succeeds.
  • The second worker tries to decrease the semaphore by -1. This blocks as it would make the semaphore negative.
  • The first worker finishes and increases the semaphore.
  • This wakes up the second worker which now decreases the semaphore.
  • When the second worker is done it also increases the semaphore.

So we have:

  • Lock mutex: decrease the semaphore by -1.
  • Unlock mutex: increase the semaphore by 1.
DarkDust
  • 90,870
  • 19
  • 190
  • 224