0% found this document useful (0 votes)
2 views39 pages

OS Process IPC Semaphore

The document discusses semaphores as synchronization tools in operating systems, highlighting their importance in solving critical section problems without busy waiting. It covers the definitions and operations of semaphores, types (counting and binary), and their implementation, as well as classical synchronization problems like the Bounded-Buffer Producer-Consumer, Readers-Writers, and Dining-Philosophers problems. Additionally, it addresses issues such as deadlock and starvation, and introduces monitors as an alternative synchronization mechanism with condition variables.

Uploaded by

nevin32.nevin
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views39 pages

OS Process IPC Semaphore

The document discusses semaphores as synchronization tools in operating systems, highlighting their importance in solving critical section problems without busy waiting. It covers the definitions and operations of semaphores, types (counting and binary), and their implementation, as well as classical synchronization problems like the Bounded-Buffer Producer-Consumer, Readers-Writers, and Dining-Philosophers problems. Additionally, it addresses issues such as deadlock and starvation, and introduces monitors as an alternative synchronization mechanism with condition variables.

Uploaded by

nevin32.nevin
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 39

Semaphore

Dr. N.Nalini
SCOPE
VIT
Semaphores
• Previous solutions are complicated and generally inaccessible to
application programmers.
• OS designers build software tools to solve critical section problem.
• Synchronization tool provided by the OS that does not require busy
waiting.
• Semaphores -- Synchronization tool that provides more sophisticated
ways (than Mutex locks) for processes to synchronize their activities.
• Semaphore S – integer variable can only be accessed via two
indivisible (atomic) operations
wait ( ) and signal ( ) - Originally called P() and V() - dutch word
P()- proberen (to test) and
V()- verhogen (increment)
Semaphores
• Shared variable : S
• Definition of the wait ( ) operation – sleep()/down()
wait (Semaphore S){ //to test
while (S <= 0) ; // busy wait
S = S – 1;
}
• Definition of the signal ( ) operation – wake-up()/up()
signal (Semaphore S){ //to increment
S = S + 1;
}
When one process modifies the semaphore value, no other process can simultaneously modify the
semaphore value. Also in wait(S), the testing of the integer value of S (S <= 0), as well as possible
modifications (S=S-1), must be executed without interrruption.
Critical Section of n Processes
• Shared data: semaphore mutex = 1;
• Process Pi

do {
wait(mutex);

critical section

signal(mutex);

remainder section
} while (true);
Types of semaphores

• There are counting and binary semaphores in the operating systems.


• Counting semaphores value can range over an unrestricted domain.
• Used to control access to a given resource consisting a number of instances.
• The semaphore is initialized to the number of resource available.
• Can implement a counting semaphore S as a binary semaphore.
• Binary semaphores value can range only between 0 and 1.
• like as a mutex lock
• It can have only two values – 0 and 1. Its value is initialized to 1.
• It is used to implement the solution of critical section problems with multiple
processes.
Semaphore Implementation
• Must guarantee that no two processes can execute the wait() and signal() on the same
semaphore at the same time
• The semaphore definition above and all other mutual exclusion solutions given so far require
"busy waiting" (looping continuously in entry code). Busy waiting wastes CPU cycles so must be
dealt with.
• To avoid busy waiting: When a process has to wait, it will be put in a blocked queue of processes
waiting for the same event.
• Define a semaphore as a structure,

struct Semaphore
{
int value;
int List[n];
};
Semaphore S;

• Assume two simple operations:


• block() suspends the process that invokes it.
• wakeup(P) resumes the execution of a blocked process P.
Implementation
• Semaphore operations on variable S are now defined as,
wait(S) {

S.value--;
if (S.value < 0) {
add this process to S.List;
block(); //suspends, waiting state
}
}

signal(S) {
S.value++;
if (S.value <= 0) {
remove a process P from S.List;
wakeup(P); //resumes, ready state
}
}
• Here, semaphore value may be negative. If it is, its magnitude is the number processes waiting on
that semphore.
• abs(value) shows the number of blocked processes. value < = 0 means that there is a process to
wakeup.
Semaphore as a General Synchronization Tool

Execute instruction B in Pj only after instruction A executed in Pi


Use semaphore flag initialized to 0

process Pi process Pj

 
instruction A wait(flag);
signal(flag); instruction B
Note:
Semaphores can solve various synchronization problems. System must quarantee that no
two processes can execute wait() and signal() operations on the same semaphore at the
same time. Two operations are executed atomically.
Classical Problems of Synchronization

• Classical problems used to test newly-proposed synchronization


schemes

• Bounded-Buffer Producer-Consumer Problem

• Readers and Writers Problem

• Dining-Philosophers Problem
Bounded-Buffer Producer-Consumer Problem
• n buffers, each can hold one item
• Shared data
int n; /*# of slots in the buffer*/
Three semaphores full = 0, /*# of full buffers*/
empty = n, /*# of empty buffers*/
mutex = 1; /*for access to the buffer pool */
Producer process
do { Consumer process
… do {
produce an item in nextp wait(full);
… wait(mutex);
wait(empty); //decrement empty …
wait(mutex); //lock remove an item from buffer to nextc
… …
add nextp to buffer signal(mutex);
… signal(empty);
signal(mutex); //release …
signal(full); //increment full consume the item in nextc
} while (true); …
} while (true);
Readers-Writers Problem
• A data set is shared among a number of concurrent processes
• Readers – only read the data set; they do not perform any updates
• Writers – can both read and write
• Problem – allow multiple readers to read at the same time
• Only one single writer can access the shared data at the same time
• Several variations of how readers and writers are considered – all
involve some form of priorities
• Shared Data
• Data set
• Semaphore rw_mutex initialized to 1
• Semaphore mutex initialized to 1
• Integer read_count initialized to 0
Readers-Writers Problem
Shared data
• int read_count = 0; /* number of readers currently reading the object */
• Two semaphores mutex = 1, /* controls access to read_count*/
rw_mutex = 1; /* controls entry to a writer or first or last reader */
Writer process Reader process
do{
wait(mutex); //reader wants enter to CS
do{ read_count++; //no.of readers incr by 1
wait(rw_mutex); if (read_count == 1) //first reader
wait(rw_mutex); //writer must have to wait
… signal(mutex);
writing is performed …
reading is performed
… …
signal(rw_mutex); wait(mutex); //reader wants to leave after reading
} while (true); read_count--;
if (read_count == 0) //last reader
signal(rw_mutex);
signal(mutex);
} while(true);
Dining-Philosophers Problem
• Five philosophers are sitting around a
table. Each philosopher has a plate in
front him/her. Between each plate
there is a chopstick.
• A philosopher is either “thinking” or
“eating”. When a philosopher gets
hungry he/she tries to get the 2
chopsticks on his/her left and right.
Having obtained both chopsticks the
philosopher can eat.They cannot have
both chopstick at the same time.
• When finished eating, the philosopher
puts both chopsticks down, and
resumes thinking.
Dining-Philosophers Problem
Shared data
semaphore chopstick[5]={1,1,1,1,1};
Philosopher i:
do {
wait(chopstick[i]);
wait(chopstick[(i+1) % 5]);

//eat

signal(chopstick[i]);
signal(chopstick[(i+1) % 5]);

//think

} while (true);
Dining-Philosophers Problem

Deadlock occurs if each philosopher starts by picking his/her


left chopstick(or the right one)!

There are several methods that ensure freedom from


deadlocks:
Allow at most four philosophers to be sitting simultaneously at the table while
maintaining five chopsticks!
Allow a philosopher to pick up his/her chopsticks only if both chopsticks are
available.
Problems with Semaphores

Incorrect use of semaphore operations:


semaphore mutex=1;

• signal (mutex) …CS... wait (mutex)


//several processes may be in their CSs at the same time

• wait (mutex) …CS... wait (mutex)


//deadlock will occur

• Omitting of wait (mutex) or signal (mutex) (or both)


//either ME will be violated or deadlock will occur.

Deadlock and starvation are possible.


Semaphore - Deadlock and Starvation
• Deadlock – two or more processes are waiting indefinitely for an event that can be
caused by only one of the waiting processes.
• Let S and Q be two semaphores initialized to 1
P0 P1
wait(S); wait(Q);
wait(Q); wait(S);
 
signal(S); signal(Q);
signal(Q); signal(S);
• P0 executes wait(S) and P1 executes wait(Q), when P0 executes wait(Q), it must wait
until P1 executes signal(Q). Similarly, when P1 executes wait (S), it must wait until P0
executes signal (S).
• Since these signal() operations cannot be executed, P1 and P2 are deadlocked.
• A set of processes in deadlocked state when every process in the set is waiting for an
event that can be caused only by another process in the set.
• Starvation – indefinite blocking. A process may never be removed from the semaphore
queue in which it is suspended.
Monitors
• A high-level abstraction that provides a convenient and effective
mechanism for process synchronization
• Abstract data type, internal variables only accessible by code within
the procedure
• Only one process may be active within the monitor at a time
• Pseudocode syntax of a monitor:
monitor monitor-name
{
// shared variable declarations
procedure P1 (…) { …. }

procedure P2 (…) { …. }

procedure Pn (…) {……}

initialization code (…) { … }


}
Monitors
• A monitor is a synchronization tool designed to make a programmer's life simple. A
monitor can be thought of as a conceptual box.
• A programmer can put functions/procedures/methods into this box.
• The monitor makes him a very simple guarantee: only one function within the monitor
will execute at a time -- mutual exclusion will be guaranteed.
• Furthermore, the monitor can protect shared data. Data items declared within the
monitor can only be accessed by functions/procedures/methods within the monitor.
– Therefore mutual exclusion is guaranteed for these data items. Functions/procedures/methods outside
of the monitor can not corrupt them.
• If nothing is executing within the monitor, a thread can execute one of its
procedures/methods/functions. Otherwise, the thread is put into the entry queue and
put to sleep. As soon as a thread exits the monitor, it wakes up the next process in the
entry queue.
Schematic view of a Monitor
Monitor
• We consider that threads executing
within the monitor may require an
unavailable resource.
• When this happens, the thread waits for
this resource, using the wait operation of
a condition variable.
• At this point, another thread is free to
enter the monitor (from enter queue).
Monitor Implementation Using Semaphores

• Variables

semaphore mutex
mutex = 1

• Each procedure P is replaced by

wait(mutex);

body of P;

signal(mutex);

• Mutual exclusion within a monitor is ensured


Condition Variable in Monitor
• The condition variable is a synchronization primitive that provides a queue for threads waiting for a resource.
• A thread tests to see if the resource is available.
– If it is available, it uses it.
– Otherwise it adds itself to the queue of threads waiting for the resource.
• When a thread has finished with a resource, it wakes up exactly one thread from the queue (or none, if the queue
is empty).
• In the case of a sharable resource, a broadcast can be sent to wake up all sleeping threads.
• Proper use of condition variables provides for safe access both to the queue and to test the resource even with
concurrency. The implementation of condition variables involves several mutexes.
• Condition variables support three operations:
– wait - add calling thread to the queue and put it to sleep
– signal - remove a thread form the queue and wake it up
– broadcast - remove and wake-up all threads on the queue
• When using condition variables, an additional mutex must be used to protect the critical sections of code that test
the lock or change the locks state.
Monitor with Condition Variables
Condition Variables
• condition x, y;
• Two operations are allowed on a condition
variable:
– x.wait() – a process that invokes the operation is
suspended until x.signal()
– x.signal() – resumes one of processes (if any) that
invoked x.wait()
• If no x.wait() on the variable, then it has no effect on
the variable
Usage of Condition Variable Example
• Consider P1 and P2 that that need to execute two statements S1 and S2 and the
requirement that S1 to happen before S2
– Create a monitor with two procedures F1 and F2 that are invoked by P1 and P2
respectively
– One condition variable “x” initialized to 0
– One Boolean variable “done”
– F1:
S1;
done = true;
x.signal();
– F2:
if done = false
x.wait()
S2;
Monitor Implementation Using Semaphores

• Variables

semaphore mutex; // (initially = 1)


semaphore next; // (initially = 0)
int next_count = 0; // number of processes waiting
inside the monitor

• Each function P will be replaced by

wait(mutex);

body of P;

if (next_count > 0)
signal(next)
else
signal(mutex);

• Mutual exclusion within a monitor is ensured


Implementation – Condition Variables
• For each condition variable x, we have:

semaphore x_sem; // (initially = 0)


int x_count = 0;

• The operation x.wait() can be implemented as:

x_count++;
if (next_count > 0)
signal(next);
else
signal(mutex);
wait(x_sem);
x_count--;
Implementation (Cont.)
• The operation x.signal() can be implemented as:

if (x_count > 0) {
next_count++;
signal(x_sem);
wait(next);
next_count--;
}
Resuming Processes within a Monitor
• If several processes queued on condition variable x, and
x.signal() is executed, which process should be resumed?
• FCFS frequently not adequate
• Use the conditional-wait construct of the form
x.wait(c)
where:
– c is an integer (called the priority number)
– The process with lowest number (highest priority) is scheduled
next
Single Resource allocation
• Allocate a single resource among competing processes using priority numbers that specifies the
maximum time a process plans to use the resource

R.acquire(t);
...
access the resurce;
...

R.release;

• Where R is an instance of type ResourceAllocator


Single Resource allocation

• Allocate a single resource among competing processes using priority numbers


that specifies the maximum time a process plans to use the resource
• The process with the shortest time is allocated the resource first
• Let R is an instance of type ResourceAllocator (next slide)
• Access to ResourceAllocator is done via:

R.acquire(t);
...
access the resurce;
...
R.release;

• Where t is the maximum time a process plans to use the resource


A Monitor to Allocate Single Resource
monitor ResourceAllocator
{
boolean busy;
condition x;
void acquire(int time) {
if (busy)
x.wait(time);
busy = true;
}
void release() {
busy = false;
x.signal();
}
initialization code() {
busy = false;
}
}
Single Resource Monitor (Cont.)
• Usage:
acquire
...
release
• Incorrect use of monitor operations
– release() … acquire()
– acquire() … acquire())
– Omitting of acquire() and/or release()
Monitor Solution to Dining Philosophers
monitor DiningPhilosophers // monitor
{
enum {THINKING; HUNGRY, EATING} state [5];
condition self [5];

void pickup (int i) {


state[i] = HUNGRY;
test(i);
if (state[i] != EATING)
self[i].wait;
}

void putdown (int i) {


state[i] = THINKING;
// test left and right neighbors
test((i + 4) % 5);
test((i + 1) % 5);
}
Monitor Solution to Dining Philosophers (Cont.)
void test (int i) {
if ((state[(i + 4) % 5] != EATING) &&
(state[i] == HUNGRY) &&
(state[(i + 1) % 5] != EATING) ) {
state[i] = EATING ;
self[i].signal () ;
}
}

initialization_code() {
for (int i = 0; i < 5; i++)
state[i] = THINKING;
}
}
Solution to Dining Philosophers (Cont.)
 Each philosopher “i” invokes the operations pickup() and
putdown() in the following sequence:

DiningPhilosophers.pickup(i);

/** EAT **/

DiningPhilosophers.putdown(i);

 No deadlock, but starvation is possible

You might also like