The mechanisms for synchronization are divided
Abstract into four types based on their level of
implementation and support: software only,
hardware support, operating-system support, and
This paper describes what semaphores are and language support. In addition, hybrid solutions
throws light on different types of semaphores exist that combine more than one approach
(counter, binary, tagged) and how can we use them
to solve the classic problems like Dining 2. The Terminologies
Philosopher’s Problem, Barber Shop Problem and
Producer Consumer Problem etc. of Process We use P to denote a process. Unless otherwise
Synchronization. Here we analyse the advantages stated, we assume only two processes P0 and P1 for
and disadvantages of using semaphores and how simplicity. The general structure of any process P0
can the same be implemented. In the end we have is as follows Repeat Entry section (E) Critical
proposed our own method for process Section (C) Exit Section (X) Remainder Section
synchronization. (R) until false We use C’, E‘, etc. to refer to the
corresponding sections of process P1. Throughout
the paper we mean P -> C to mean process P
1. Introduction requests the Critical Section or is waiting to get
into the Critical Section and P <- C to mean P gets
Process synchronization is a fundamental the Critical Section.
problem in operating system design and
implementation whenever two or more processes
must coordinate their activities based upon a 3. Semaphores
condition.
In a system comprising of ‘n’ processes each Semaphores are data structures consisting of an
process has a segment of code called a Critical identifier, a counter, and a queue.Processes waiting
Section [1] in which the process may be changing on a semaphore are blocked and placed on the
common variables, updating a table, writing a file queue; processes signalling a semaphore may
and so on. unblock and remove a process from the queue; and
Any solution to the synchronization problem is said the counter maintains a count of waiting processes.
to be “correct” only if it satisfies the four Not only can semaphores be used for mutual
conditions listed below. [2] exclusion, but they also provide a mechanism to
solve other synchronization problems [1]
1. Mutual Exclusion (m) : If P is executing in its
Critical Section, then no other process can be
executing in the Critical Section. We say a Critical 4. Implementing Semaphores
Section algorithm violates ‘m’ if it is possible, no
matter how unlikely ,that two processes can have Hemmendinger has presented a functionally
their program counter (PC) pointing at the Critical correct implementation of general semaphores
Section instructions at the same time. using only binary semaphores for concurrency
control [3]
2. Strict Progress (p) : For multiple processes if no
process is executing in Critical Section and there type
exists some process that wish to enter their Critical semaphore -- record
Sections, only these processes participate in the mutex = 1,
delay = 0: binary_semaphore;
decision of which will enter its Critical Section
count = 0: integer;
next and this decision cannot be postponed end;
indefinitely. One will surely enter its Critical
Section. Procedure P(var s:semaphore)
begin
3. Bounded Waiting (b): If P <- C and Q -> C , PB(s.mutex);
then there is a least bound beta on the number of s.count := s.count - 1;
times P may exit the Critical Section and return if s.count < 0 then
begin
before Q -> C. VB(s.mutex);
PB(s.delay);
4. Starvation Free (s_f):If P -> C then P cannot wait End
indefinitely before P <- C. else
VB(s.mutex)
end;
Procedure V(var s:semaphore); operator that has a semaphore value of zero, that
begin process is blocked; otherwise, the semaphore value
PB (s.mutex); is decremented by one and the process continues.
s.count :-- s.count - 1;
When a process executes a SIGNAL operator and
if s.count < 0 then
VB(s.delay) there are waiting (blocked) processes, one of the
Else waiting processes is activated (placed on the
VB(s.mutex) processor ready queue); otherwise, if there are no
End; waiting processes, the semaphore value is
incremented by one. It is assumed that processes
Figure1: Hemmindinger Construction blocked by semaphores loose the processor and
enter a waiting list rather than retaining the
If the value of s.count is negative (and, processor and busy-waiting. Also, we assume the
consequently, there are a number of processes waiting list queue organization is first-in-first-out.
suspended on s.delay), this implementation will not [5] defines certain learning patterns like ‘I’ll do it
permit a sequence of V operations to be executed. for you’ and ‘Pass the Baton’ that helps explaining
There will be a lockstep sequence of a V followed the concept of semaphores and common problems
by the completion of a suspended P until s.count that one face while implementing semaphores.
becomes non-negative. Such restricted behaviour
could possibly have substantial performance
5. Types of Semaphores
penalties in certain system context.
Alternative solution to the problem of constructing
Binary Semaphores
general semaphores from binary semaphores is
presented in Figure 2. Counting Semaphores
Tagged Semaphores
type
semaphore = record 5.1 Binary Semaphores[6]
mutex = 1,
delay = 0: binary_semaphore; Binary semaphores are used to provide
count = 0,
wakecount = 0: integer
exclusive locking for a thread on a resource. Only
end; one thread at a time may "hold" the semaphore. All
others must wait until their turn with the
Procedure P(var s:semaphore) semaphore. If you want to lock access to a
begin potentially blocking resource, you should acquire a
PB(s.mutex); semaphore for that resource just before accessing it.
s.count := s.count - 1; and release the semaphore upon completing your
if s.count < 0 then
access to the resource. The following code block
begin
VB(s.mutex); defines the interface to a monitor implementing a
VB(s.delay); binary semaphore.
PB(s.mutex);
s.wakecount := s.wakecount - 1; protected type Binary_Semaphore is
ff s.wakecount > 0 then VB(s.delay) entry Acquire;
end; procedure Release;
VB(s.mutex) private
end; Locked : Boolean := False;
end Binary_Semaphore;
Procedure V(var s:semaphore);
begin Figure 3 : Binary Semaphores
PB(s.mutex);
s.count :-- s.count + 1; This monitor has two operations defined. The entry
if s.count < 0 then Acquire allows a thread to acquire the semaphore if
begin no other task currently holds the semaphore. The
s.wakecount := s.wakecount + 1;
VB(s.delay)
procedure Release unconditionally releases the
end; semaphore. The private data for this monitor is a
VB(s.mutex); single boolean value, Locked, which is initialized to
end; False.
The actual workings of the monitor are specified in
Figure 2: The Less Restrictive Construction the body of the protected type.
In the above figure semaphores are basically protected body Binary_Semaphore is
implemented using two atomic[4] methods P (wait) entry Acquire when not Locked is
and V(signal) when a process executes a WAIT begin
Locked := True;
end Acquire; Note that the Release procedure uses a conditional
procedure Release is to ensure that Count is never assigned a negative
begin value.
Locked := False;
end Release;
end Binary_Semaphore; 5.3 Tagged Semaphores[7]
Figure 4: Binary Semaphores(2) Tagged semaphores are also called identified
semaphores, with which operations associated are
Note that you can only acquire the binary Tagged_Wait and Tagged_Signal which
semaphore when it is not already locked. Acquiring correspond respectively to standard Wait and
the semaphore causes it to be locked. The Release Signal primitives, and both are indivisible. The
procedure simply unlocks the semaphore. difference between a standard semaphore and a
tagged semaphore is that the former has only one
5.2 Counting Semaphores sub item which represents available resources,
waiting processes, all resources having been
Sometimes you want to access a resource with occupied and no process being waiting when its
the ability to handle a limited number of value is positive, negative and zero, respectively,
simultaneous accesses. In this case, you will want while a tagged semaphore has three sub items: S.R,
to use a counting semaphore. This variation on the S.P and S.T which represents available resources
semaphore allows up to a predetermined maximum (the initial value is the amount of resources N),
number of threads or tasks to hold the semaphore waiting processes (the initial value is zero) and a
simultaneously. The interface for a counting tag of identity of the users of the resources (like
semaphore looks a lot like the interface for a binary sex, organization, etc. ), respectively. When all
semaphore. resources are available, the tag doesn’t matter, (it
can be viewed as having a special "null'). The
protected type values of all the three sub items can' t be updated
Counting_Semaphore(Max : Positive) is elsewhere except the two primitives.
entry Acquire; ‘Tagged_Wait’ is used to apply resources, which
procedure Release;
private has two parameters a value parameter Tag,
Count : Natural := 0; representing the tag of calling processes (not the
end Counting_Semaphore; semaphores), and a variable parameter S,
representing the tagged semaphore. [7]
Figure 5: Counting Semaphore
Assume there is a toilet having N cells but does not
In this case, when the semaphore is created you separate lady's from man's. When someone is in,
must specify the maximum number of tasks you anyone of opposite sex is forbidden to enter (can be
want to simultaneously hold this semaphore. The tagged using a notice board), even though there
private data for this semaphore is a simple integer are empty cells. However, unless all N cells are
value, counting the current number of tasks occupied, anyone of same sex can enter. When
currently holding the semaphore. In the case of a nobody is in, anyone can enter.
counting semaphore, the boundary condition for the Toileting problems can be solved easily using
Acquire entry is that the Count cannot exceed the tagged semaphores. Before entering, the primitive
value of Max. The implementation of the counting Tagged_Wait (Sex, Sem)
semaphore simply manipulates the Count. is called, where Sex is the sex of the one who want
to enter, Sem is the tagged semaphore representing
protected body Counting_Semaphore is cells of the toilet and the primitive
entry Acquire when Count < Max is
Signal(Sem)
begin
Count := Count + 1; is just called when someone quits.
end Acquire;
Although tagged semaphores were introduced and
procedure Release is discussed beginning with the example of resource
begin allocation,tagged semaphores can also be used for
if Count > 0 then processes to synchronize and mutually exclude
Count := Count - 1; each other. When the initial value of S.R is 1,
end if;
end Release;
tagged semaphores are degenerated to standard
end Counting_Semaphore; semaphores (the tag sub item doesn’t matter by
then). When using a tagged semaphore with a
Figure 6: Counting Semaphore(2) special “null” as its tag, the semaphore is
degenerated to a standard multi-valued semaphore.
When desired that only those processes having an
identical nature can proceed concurrently, tagged wait(mutex2);
semaphores can be used as well (S.R now enqueuel(custnr);
represents not the number of available resources, signal(cust_ready);
but processes that can proceed concurrently). We signal(mutex2);
can conclude that tagged semaphores are wait(finished[custnr]);
generalization of standard semaphores and standard signal(leave_b_chair[custnr]);
semaphores are special cases of tagged pay;
semaphores. wait(mutex3);
enqueue2(custnr);
6. Solutions of some Classic Problems signal(mutex3);
using Semaphores wait(receipt[custnr]);
exit shop;
signal(max_capacity);
Barber Shop Problem
end;
Dining Philosopher Problem
Producer Consumer Problem
procedure barber ;
6.1 BARBER SHOP PROBLEM [9] var b_cust : integer ;
repeat
The obstacles encountered when attempting to wait(cust_ready) ;
provide tailored access to barbershop resources are wait(mutex2) ;
similar to those encountered in a real operating dequeuel(b_cust) ;
system. Assume the barbershop will eventually signal(mutex2) ;
process fifty customers, but the maximum wait(coord) ;
barbershop capacity is twenty customers . Once cut hair ;
signal(coord) ;
inside, most customers stand by the door waiting to
signal(finished[b_cust]) ;
be served, but four can sit on a sofa ,Three barbers
wait(leave_b_chair[b_cust]) ;
use three barber chairs to cut hair in the order signal(barber_chair) ;
customers come available .When finished, any until forever ;
barber can accept payment, but there is only one
cash register, so payment must be accepted for one procedure Cashier
customer at a time . The barbers must divide their var c_cust : integer ;
time between cutting hair and accepting payment . repeat
wait(payment) ;
wait(mutex3) ;
program barbershop2 ; dequeue2(c_cust) ;
signal(mutex3) ;
var max capacity, sofa, barber_chair, wait(coord) ;
cust_ready, payment, coord, rnutexl , accept pay ;
mutex2, mutex3 : semaphore ; signal(coord) ;
finished, leave_b_chair, receipt : array[1 . . signal(receipt[c_cust] ) ;
50] of semaphore ; until forever ;
count : integer ; end;
procedure customer ; begin (* main program * )
var custnr : integer ; max_capacity := 20 ; sofa := 4 ;
begin barber_chair := 3 ;
wait(max_capacity); cust_ready := 0 ; payment := 0;
enter shop; coord := 3 ; mutexl := 1 ;
wait(mutex1) mutex2 := 1 ; mutex3 := 1 ; count := 0 ;
count:= count + 1; for i = 1 to 50 do
custnr:=count; begin
signal(mutex1); finished[i] := 0 ; leave_b_chair[i] ;
wait(sofa); receipt[i] := 0 ;
wait(barber_chair); end ; (* semaphore and integer
get up from sofa; initializations * )
signal(sofa); cobegin
sit in barber chair;
customer ; . . . 50 times . . . ; if ( state[i] == HUNGRY && state[LEFT(i)]
customer ; != EATING && state[RIGHT(i)] !=
barber ; barber ; barber ; EATING )
{
cashier ;
state[i] = EATING; V(s[i]);
coend ; }
end . }
void get_forks(int i)
{
Figure 7: Barber Problem P(mutex);
state[i] = HUNGRY;
The barbers are occupied and the customer receive test(i);
V(mutex);
relatively speedy service. Even the fire marshal P(s[i]);
should be pleased since the building never exceeds }
its maximum capacity limits. Caution is in order,
however, because there is inherent danger when void put_forks(int i)
designing concurrent programs. {
P(mutex);
6.2 Dining Philosopher’s Problem [10][11] state[i]= THINKING;
test(LEFT(i));
test(RIGHT(i));
There are N philosophers sitting around a circular V(mutex);
table eating spaghetti and discussing philosophy. }
The problem is that each philosopher needs 2 forks
to eat, and there are only N forks, one between void philosopher(int process)
each 2 philosophers. Design an algorithm that the {
philosophers can follow that insures that none while(1)
{
starves as long as each philosopher eventually
think();
stops eating, and such that the maximum number of get_forks(process);
philosophers can eat at once. eat();
Here’s an approach to the Dining Philosopher put_forks(process);
that’s simple and wrong: }
}
void philosopher()
{ Figure 9: Dining Philosopher Problem(2)
while(1) {
sleep(); 6.3 PRODUCER CONSUMER PROBLEM
get_left_fork(); [12]
get_right_fork();
eat();
put_left_fork(); Typically, a bounded buffer is implemented with
put_right_fork(); one or more producer processes storing data in a
} buffer, and one or more consumer processes
} removing data from the buffer. The producer
processes must stop producing when the buffer is
Figure 8: Dining Philosopher Problem(1) full, and the consumer processes must stop
consuming when the buffer is empty. Also,some
If every philosopher picks up the left fork at the mechanism must prevent processes from
same time, none gets to eat - ever. concurrently accessing the buffer.The
Here is a solution to Dining Philosophers problem producer/consumer problem can be run on both
that provides for maximum accuracy. single and multi-processor systems. A single-
processor implementation provides fair access to
#define N 5 /* Number of philosphers */
the buffer using time slicing. In contrast, multi-
#define RIGHT(i) (((i)+1) %N)
#define LEFT(i) (((i)==N) ? 0 : (i)+1) processor systems can assign producer and
typedef enum { THINKING, HUNGRY, consumer tasks to separate processors.
EATING } phil_state;
phil_state state[N]; program prod_cons
semaphore mutex =1;
semaphore s[N]; /* one per philosopher, all var in,out: integer;
0 */ buff: array[0..n- 1] of integer;
not_empty, not_full, mutex: semaphore;
void test(int i)
{ procedure insert(x: integer);
begin
WAIT(not_full); synchronization and mutual exclusion Semaphores
WAIT(mutex); perform best when single-processor context
buff[in] := x; switching is considered. With semaphores, context
SIGNAL(mutex);
switching is necessary only when a process is
in := (in+l) rood n;
SIGNAL(not_empty); blocked by a full or empty buffer, or when the
end; process's time quantum expires. With monitors, the
right conditions (when the buffer is full or empty)
procedure remove(var y: integer); can cause a parade of unnecessary context switches
begin that have an effect similar to thrashing in memory
WAIT(not_empty); management paging systems. This context
WAIT(mutex); thrashing allows progress to be made towards
y := buff(out);
SIGNAL(mutex); completing the program, but at a slower pace.
out := (out+l) rood n; The design decision to protect all code inside a
SIGNAL(not_full); monitor from concurrent access represents an
end; unfortunate overkill when task granularity is
considered. Semaphores are better in this respect.
procedure producer;
var item: integer;
repeat
8. Why Not Semaphores
generate item;
insert(item); Semaphores provide us with convenient and
until false; effective solution to Process Synchronization
problem but using them incorrectly causes timing
procedure consumer; errors that are difficult to detect.[13]
var item: integer;
repeat
Software engineers would probably prefer monitors
remove(item);
use item; . tasking to semaphores because those Mechanisms
until false; permit the encapsulation and hiding of
synchronization details from users. The code would
be less susceptible to user generated side effects.
[12]
begin {main program}
in := 0; out := 0; mutex := 1; not_full := n;
not_empty := 0;
cobegin 9. Proposed Method
producer;
consumer; After going through various research papers on
coend; process synchronization we present here our
end;
method for synchronization.
Problem of Synchronization arises due to the fact
Figure10: Consumer Buffer Problem
that more than one process is trying to access and
change one of the common variables.
One producer process and one consumer process
If somehow we can set a particular sequence in
execute concurrently in figure 10. Producer
which process will access these common variables
repeatedly generates an item and then calls upon
then we have a solution at hand.
insert to place the item in a buffer. Consumer
In this proposed method we maintain a separate
repeatedly calls upon remove to get an item from
queue that will hold critical section of the
the buffer and then consumes the item. In this
processes. When a process requests for a CPU in
implementation, the only time producer and
CS(critical section) then instead of giving CPU
consumer lose the processor is when the time
time we copy these commands and store it in a
quantum expires or they are blocked by a WAIT
queue and a flag is set that shows that this process
operator during insert or remove procedure calls.
is waiting for this queue to get executed.
Therefore, context switching is necessary only on
This Queue will itself get executed periodically
those occasions. Notice also that producer is
where each instruction would be fetched from this
prevented from accessing the buffer while
queue and will be executed. As and when all
consumer is accessing it (and vice versa).
instructions related to one particular CS get
executed its flag is set or it is signalled to the
7. Why Semaphores waiting process that its CS is executed and now it
can proceed with the Remainder Section.
Semaphores are both powerful in expressiveness
and simple in mechanism, which makes them easily
understood and used to deal with most problems
Since all the Critical Section Code is executed [9] Ralph C .Hilzer, “Concurrency With Semaphores”
serially there is no possibility that two processes Department of Computer Science,California State
will ever be executing CS simultaneously. Hence University, Chico
Mutual Exclusion is satisfied.
[10] Kwok-bun Yue “Dining Philosophers Revisited”
University of Houston
Also any process waiting in this Queue will wait as
long as CS of the Processes above it are not getting [11] Peter Kokol, “ DINING PHILOSOPHERS - AN
executed. Thus Decision on how long a given EXERCISE IN USING THE JSD”,The Faculty of
process have to wait before entering CS is Technical Sciences University.
governed completely by CS and Entry Section.
[12] Ralph C. Hilzer, Jr. “Synchronization of the
For bounded waiting we can implement Priority Producer/Consumer Problem using Semaphores,
Monitors, and the Ada Rendezvous”,Department of
Queue and can increase the priority of waiting
Computer Science,California State University
process if the wait is beyond some threshold.
[13]Silberschatz. A., Galvin. P. B., Gagne. G.,“Operating
So we are able to implement process System Concepts”, Sixth Edition, John Wiley and Sons
synchronization using a priority queue. Inc., ISBN 0-471-41743-2, June 2001.
10. Conclusion
Here we have described what semaphores are and
how can they be implemented. We also touched
upon types of semaphores and saw how we can
implement various classical problems of
synchronization using semaphores.
While compiling up this paper we developed one of
our own method for process synchronization where
we made use of a priority queue for synchronizing
processes.
11.References
[1] CRAIG E. WILLS “ Process Synchronization and
IPC”, Published by ACM.
[2] Mithun Acharya and Robert Funderlic , “ ‘Laurel and
Hardy’ Model for Analyzing Process Synchronization
Algorithms and Primitives” ,Published By ACM.
[3 ] Phil Kearns “A Correct and Unrestrictive
Implementation of General Semaphores”,
Department of Computer Science
The College of William and Mary Williamsburg
[4] D. B. Lomet IBM T.J. Watson Research Center,
“PROCESS STRUCTURING, SYNCHRONIZATION,
AND RECOVERY USING ATOMIC ACTIONS”
[5] Kenneth A. Reek, “Design Patterns for
Semaphores”, Published by ACM.
[6] Leszek Kotulski, “Comments on implementation of P
and V primitives with help of binary semaphores.
Department of Computer Science”
Jagellonian University.
[7] BaowenXu, “Tagged Semaphores”
Department of Computer Science and Engineering
Southeast University.
[8] John A. Trono, “Comments on Tagged Semaphores
Computer Science Department”