CIS 307: TOPIC: Semaphores

Semaphores are treated in Tanenbaum Section 2.2.5

Definition and initial implementation

People use the term "Semaphore" to refer to a variety of synchronization mechanisms. Here by "Semaphore" we mean the "non-busy-waiting" analog of SpinLocks. We show a possible implementation for semaphores. For now assume that semaphore's operations are atomic.

	type semaphore = record
			    count : integer;
  1.			    q     : queue of processes;
			 end record;
	procedure initsem (s : in out semaphore; n : integer) is
	begin
	   s.count := n; initialize s.q to the empty queue;
	end;
	procedure P(s : in out semaphore) is
	begin
  2.	   s.count := s.count - 1;
  3.	   if s.count < 0 then 
  4.	      Remove this process from Running, add it 
	              to s.q, and reschedule;
	end;
	procedure V(s : in out semaphore) is
	begin
  5.	   s.count := s.count + 1;
  6.	   if s.count <= 0 and s.q is not empty then
  7.	      Remove a process from s.q, add it to the Ready 
		      Queue, and reschedule;
	end;

Comments

Using semaphores we can achieve a number of different behaviors:

Nutt's Implementation

Here we show code similar to the code used by G.J.Nutt in his Operating Systems book. This code implements N semaphores for a multiprocesing system.

#define	 N   ..         /* The number of semaphores */

int      value[N];	/* Keeps the count for the semaphores   */
boolean  sem[N];	/* Spinlocks to protect critical region */
			/*   of semaphore */
boolean  hold[N];	/* Used to temporarily "enqueue" tasks  */
			/* waiting on sem */

void initsem(int s, m) {
	value[s] = m; sem[s] = FALSE; hold[s] = TRUE;}
void P(int s) {
	while (TS(sem[s]));	/* Lock */
	value[s]--;
	if (value[s] < 0) {
	   sem[s] = FALSE;	/* Unlock */
	   while(TS(hold[s])) yield(Q); /* Here the process enters */
			/* a new Critical Region where it gives    */
			/* control to Q, a scheduler. It is a loop */
			/* since we may repeatedly be given control*/
			/* back from yield and find a blocked semaphore.*/
	}else
	   sem[s] = FALSE;}	/* Unlock */
void V(int s){
	while (TS(sem[s]));	/* Lock */
	value[s]++;
	if (value[s] <= 0){	/* Somebody is waiting in hold to enter CR*/
	   while (!hold[s]);	/* We check if there is a concurrent V. */
				/* It is a loop */
				/* because we might have two or more */
				/* concurrent V operations executing.*/
	   hold[s] = FALSE;	/* Here we free a process waiting in P.*/
	}
	sem[s] = FALSE;}	/* Unlock */

Implementation of Semaphores in XINU

You may examine the implementation of semaphores in XINU. Examine in particular the files sem.h, wait.c, and signal.c. Do you think that this implementation works only in a shared memory mutiprocessing system? or only in a single processor system?

An implementation for testing programs that use semaphores

Here is code that implements semaphores as pipes. Of course nobody would ever think to use such an implementation in practice. This code is shown here for two reasons. Firstly, it can be used to test concurrent programs with semaphores. Second, it reminds us that IPC primitives can be implemented in terms of each other. That is, IPC primitives are chosen not just on the basis of functionality, but also on the basis of performance (things like data rate and latency).

ingargiola.cis.temple.edu