Transcript Slide 1

Semaphores, Locks and
Monitors
By Samah Ibrahim
And Dena Missak
Semaphore Definition
A semaphore is a synchronization construct that can
be used to provide Mutual Exclusion and Conditional
Synchronization.
Mutual exclusion means that only one thread can have control
over a shared resource at a certain point in time
Conditional synchronization :refer to synchronization using
condition variables .
Two operations, Wait and Signal, are defined on condition
variables.
Wait: suspends/blocks execution of the calling process if a
certain condition is true
Signal: wake up a waiter, if any.
It is a shared object that can be manipulated only by
two atomic operations, P and V.
It is a non-negative integer variable
Counting & Binary Semaphores
There are two types of semaphores:
Counting Semaphore
Binary Semaphore.
Counting Semaphore can be used for
mutual exclusion and conditional
synchronization.
Binary Semaphore is specially designed
for mutual exclusion.
Counting Semaphore
A counting semaphore can be considered
as a pool of permits.
A thread uses P operation to request a
permit. If the pool is empty,
the thread waits until a permit becomes
available.
A thread uses V operation to return a
permit to the pool.
An Object Oriented Definition
A counting semaphore can be defined in an
object-oriented manner as shown below:
class CountingSemaphore {
private int permits;
public CoutingSemaphore (int initialPermits) {
permits = initialPermits; }
public void P() { ... }
public void V() { ... } }
An Implementation Sketch
Here is a sketch of one possible implementation
of methods P() and V():
Semaphore -> P()
If permits >0,then decrement permits by 1
otherwise "wait" until permits>0 and then decrement
Semaphore -> V()
Increment permits by 1
Wake up a thread waiting in P()
No thread that is blocked on a P() operation remains
blocked if the V() operation on the semaphore is
invoked infinitely often
In practice, FIFO is mostly used, transforming the
set into a queue.
Binary Semaphore
A binary semaphore must be initialized
with 1 or 0,
and the completion of P and V
operations must alternate.
Why must P and V
alternate?
Answer
if a binary semaphore is initialized with
1, and a certain thread obtained that
permit by calling P() and then another
thread calls P() again,that thread will be
blocked unless V() is called.
If the semaphore is initialized with 1,
then the first completed operation must
be P. If the semaphore is initialized
with 0, then the first completed
operation must be V.
P operation can be blocked, if it
attempted in a consecutive manner.
Counting vs. Binary Semaphore
Counting Semaphore
Can take any initial value
V operation never blocks
Completed P and V operations do not have to
alternate
V could always be the first completed operation
Binary Semaphore
Can only take 0 or 1
Both P and V operation may block
Completed P and V operations must alternate
If the initial value is 0, the first completed
operation must be V; if the initial value is 1, the
first completed operation must be P.
Locks
Lock provide mutual exclustion
A lock defines two types of operations:
Lock(): wait until lock is free, then grab it
Unlock(): release the lock, waking up a
waiter,if any
Lock Ownership
A lock can be owned by at most one thread at
any given time.
A thread that calls lock becomes the owner of
a lock if the lock is not owned by any other
thread; otherwise, the thread is blocked.
The owner of a lock can release the ownership
by calling unlock.
Important: The owner of a lock is not blocked
if it calls lock again.
However, the owner must call unlock the same
number of times to release the ownership.
Binary Semaphore vs. Lock
Binary Semaphore
Has no concept of ownership
Any thread can invoke P or V operations
Consecutive P operations will be blocked
Need to specify an initial value
Lock
A lock can be owned by at most one thread at any
given time
Only the owner can invoke unlock operations
The owner can invoke lock (or unlock) operations in
a row.
Does not have to be initialized
Lock vs. Binary Semaphore
Lock L = new Lock ();
BinarySemaphore s = new BinarySemaphore (1);
T1:
L.lock();
L.lock();
T2:
s.P();
s.P();
T1:
L.lock();
T1:
s.P();
T2:
L.unlock();
T2:
s.V();
Abstract Definition
Java does not provide any semaphore
classes. We can however simulate
semaphores in Java.
public abstract class Semaphore {
protected int permits;
protected abstract void P() ;
protected abstract void V() ;
protected Semaphore (int initialPermits) {
permits = initialPermits; } }
CountingSemaphore
public final class CountingSemaphore extends
Semaphore {
public CoutingSemaphore (int initialPermits) {
super(initialPermits;) }
synchronized public void P () {
if (permits >0) permits --;
else {
try { wait (); } catch (InterruptedException ex) {};
permits --;
} }
synchronized public void V () {
permits++;
if (permits <=1) {
//it means the permits was zero
notify (); } } } // wake up the threads if any
BinarySemaphore
public final class BinarySemaphore extends Semaphore {
public BinarySemaphore (int initialPermits) {
super(initialPermits);
if (initialPermits != 0 || initialPermits != 1) {
throw new IllegalArgumentException( initial value must be 0 or 1.
); } }
synchronized public void P () {
while (permits == 0) { //no permit, queue the thread
try { wait (); } catch (InterruptedException ex) {}; }
permits = 0;
//a thread will obtain a permit
notifyAll (); } // notify the other threads that permits=0
synchronized public void V () {
while (permits == 1) { //wait until the permit=0, then reset it
try { wait (); } catch (InterruptedException ex) {}; }
permits = 1;
notifyAll (); } } //notify the threads that a permit exist
Lock Implemetation
public final class Lock {
private Thread owner = null;
private int waiting = 0; //to count how many threads are waiting
public int count = 0; //to count how many times the object is locked
public boolean free = true; //means the lock is free
public synchronized void lock () {
if (free) {
count = 1; free = false;
owner = Thread.currentThread ();}
else if (owner == Thread.currentThread()) { ++ count; }
else {
++ waiting;
try { wait(); } catch (InterruptedException ex) {}
count = 1; owner = Thread.currentThread ()}}
Lock Implemetation continued
public synchronized void unlock () {
if (owner != null) {
if(owner == Thread.currentThread ()) {
-- count;
if(count == 0) {
owner = null;
if (waiting > 0) {
-- waiting;
notify();}
else { free = true; return; }
}else return;}
}throw new OwnerException ();}}
What are monitors?
Monitors provide a structured
concurrent programming primitive, which
is used by processes to ensure exclusive T1
access to resources, and for
synchronizing an communicating among
users.
To synchronize tasks within the monitor,
a condition variable is used to delay
processes executing in a monitor.
Signal
Two operations, Wait and Signal, are
defined on condition variables.
Wait: suspends/blocks execution of the
calling process if a certain condition is true
Signal: wake up a waiter, if any.
T2
Wait
The End