Jan 24, 2010

Semaphores

Inter Process Communication

Inter-process communication (IPC) is a set of techniques for the exchange of data among multiple threads in one or more processes. Processes may be running on one or more computers connected by a network. IPC techniques are divided into methods for message passing, synchronization, shared memory, and remote procedure calls (RPC).

The method of IPC used may vary based on the bandwidth and latency of communication between the threads, and the type of data being communicated.

IPC mechanisms have many distinct purposes: for example

  • Data transfer
  • Sharing data
  • Event notification
  • Resource sharing
  • Process control

There are several reasons for providing an environment that allows process cooperation:

  • Information sharing
  • Computation speedup
  • Modularity
  • Convenience
IPC Mechanisms
  • Primitive
    • Unnamed pipe
    • Named pipe (FIFO)
  • System V IPC
    • Message queues
    • Shared Memory
    • Semaphores
  • Socket Programming

This article deals with the Semaphores.

Overview of Semaphores

Semaphore is a synchronization mechanism, which implements mutual exclusion among processes to avoid race condition to access any shared resource.

An efficient usage of shared memory is not possible without the help of semaphore. Semaphore maintains a counter to implement locking and unlocking. It avoids busy waiting. If a critical section is in use, the calling process will be removed from a run queue and put into a sleep state.

Two types of semaphore exist: binary and counting.

Semaphores are created and stored in kernel and have kernel persistence – Kernel stores in memory a data structure per semaphore set

image

If a process wants to use the shared object, it will “lock” it by asking the semaphore to decrement the counter. Depending upon the current value of the counter, the semaphore will either be able to carry out this operation, or will have to wait until the operation becomes possible.

Basic Semaphore usage

Two processes, process A and B use a semaphore to synchronize access to a shared resource.

Assume process2 is started after process1 locks semaphore successfully.

image

1) semop =-ve value, waits till semval is greater than or equal to absolute value of semop; absolute value of semop is subtracted from semval; used for locking a resource.

2) semop =-ve value, current semval = 0, which is < absolute value of semop; hence process 2 waits for semval=1.

3) semop =+ve value, does not wait; semop is added to semval; used for locking a
resource.

Basic Semaphore usage – example code
/* Process A */
#include <stdio.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <errno.h>
int main()
{
key_t keyval;
int retval, semaphoreid;
struct sembuf op[1];
union semun arg; // define as per your man pages
keyval = ftok(&#8220;/tmp/sem1", 1);
if ( keyval == -1)
{
// ftok error, return
}
semaphoreid = semget ( keyval, 1, 0600 |
IPC_CREAT); ------------à // semget (): create new semaphore or get access to
an existing semaphore Permissions to semaphore may be specified IPC_CREAT,
IPC_EXCL and IPC_PRIVATE flags as in other IPCs.
if (semaphoreid == -1)
{
// semget error, return
}
arg.val = 1;
retval = semctl( semaphoreid, 0, SETVAL, arg ); ------à // semctl(): perform control
operations on semaphore In this case, semaphore value is initialized to 1.
Note: semaphore creation and initialization are a 2-step process in Sys V IPCs and must
be done atomically.
if (retval)
{
// semctl error, return
}
op[0].sem_num = 0;
op [0].sem_op = -1; -------à // semop (): perform semaphore operations. One or more
operations can be specific, they are performed atomically i.e. all or none this semop ()
with a semop=-1 locks semaphore.
op [0].sem_flg = 0;
retval = semop (semaphoreid, op, 1);
printf("
Process A locked sem1\n");
/* Do operation on shared resource */
op [0].sem_op = 1;
retval = semop (semaphoreid, op, 1);
printf("
Process A unlocked sem1\n");
return;
}
/* Process B */
#include <stdio.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <errno.h>
int main()
{
key_t keyval;
int retval, semaphoreid;
struct sembuf op [1];
keyval = ftok (&#8220;/tmp/sem1"
, 1);
if (keyval == -1)
{
// ftok error, return
}
semaphoreid = semget (keyval, 1, 0600);
if (semaphoreid == -1)
{
-------------à // If Process B starts before Process A, then
semget () fails since semaphore is not created yet (ENOENT error)
// semget error, return
}
op [0].sem_num = 0;
op [0].sem_op = -1;
op [0].sem_flg = 0;
printf("Process B trying to lock sem1\n");
retval = semop (semaphoreid, op, 1); ---------à // This semop () waits till Process A has
unlocked semaphore.
printf("Process B locked sem1\n");
/* Do operation on shared resource */
op [0].sem_op = 1;
retval = semop (semaphoreid, op, 1);
printf("Process B unlocked sem1\n");
return;
}


Some scenarios


What happens if Process B starts running before Process A?


semget () fails with EEXIST error since semaphore does not exist.



What happens if Process A completes execution before start of Process B? Does the semaphore still exist?


Process B gets the semaphore lock immediately and runs to completion. Semaphores have kernel persistence.



semget () in Process B returns an error of EACCESS. Why is this so?

Process B does not have the required permissions. These must be specified by Process A


during semget ().



Process A aborts before unlocking the semaphore. What happens to Process B?

Process B waits forever. If process B calls semop () with a flag of IPC_NOWAIT, it


would not wait, but return with errno EAGAIN.



When is the semaphore removed from the system? Is it removed when Process B exits?

The semaphore must be deleted using semctl (). It is otherwise removed only on system


reboot.



Consider the below example code,



int perform (int semaphoreid, int val)
{
struct sembuf op [1];
op [0].sem_num = 0;
op [0].sem_op = val;
op [0].sem_flg = 0;
retval = semop (semaphoreid, op, 1); -------------à // Assume this process is blocked on
semop ().
/* Do operation on shared resource */
/* Release semaphore */
op [0].sem_op = 1;
retval = semop (semaphoreid, op, 1);
return;
}


If the semaphore is deleted by some means, then what happens to this program?


Appropriate error handling is required. In this case, semop () returns an errno of EIDRM, indicating that the semaphore has been removed. If the semaphore was deleted before the semop (), then it returns an EINVAL.



Semaphores cleanup act


Use of SEM_UNDO flag in semop () takes care of cleanup when process terminates.



In the above program, by setting the SEM_UNDO flag in semop (), the kernel updates a

‘semadj’ value. When the program terminates it ‘undoes’ the previous semop () operations thus resetting the semval.



Semaphores Attributes


Per semaphore




  • semval: current value of semaphore


  • sempid: pid of process that performed the last semop ()


  • semncnt: number of processes/threads waiting for semval to increase


  • semzcnt: number of processes/threads waiting for semval to become zero



semctl() with flag GETVAL or GETALL can be used to retrieve value of semaphore or all semaphores in set Likewise, can be set using SETVAL or SETALL.



semctl () with flags GETPID, GETNCNT, GETZCNT semncnt is incremented whenever there is a process waiting on a semop () with a negative non-zero integer.



semzcnt is incremented whenever there is a process waiting for semval to become zero. Both are decremented when the process acquires the semaphore.



Per semaphore-set




  • • Semaphore permissions

    • As specified in semget ()




  • Number of semaphores in set

    • As specified in semget () at the time of creation




  • sem_otime: time of last semop ()


  • sem_ctime: time of creation or last IPC_SET



Semaphore-set can be retrieved using semctl () and IPC_STAT flag.



References



0 comments:

Text Widget

Copyright © Vinay's Blog | Powered by Blogger

Design by | Blogger Theme by