


















Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
The monitor class boundedbuffer in java and c++, which is used to implement a bounded buffer for concurrent programming. The class has methods for deposit and withdraw operations, and uses condition variables and mutexes to ensure thread safety and synchronization.
Typology: Study notes
1 / 26
This page cannot be seen from the preview
Don't miss anything!



















4. Monitors
Problems with semaphores:-^
shared variables and the semaphores that protect them are global variables
-^
Operations on shared variables and semaphores distributed throughout program
-^
difficult to determine how a semaphore is being used (mutual exclusion or conditionsynchronization) without examining all of the code. The monitor concept was developed by Tony Hoare and Per Brinch Hansen in the early‘70’s to overcome these problems. (Same time period in which the concept ofinformation hiding [Parnas 1972] and the class construct [Dahl et al. 1970] originated.)Monitors support data encapsulation and information hiding and are easily adapted to anobject-oriented environment. 4.1 Definition of Monitors A monitor encapsulates shared data, all the operations on the data, and anysynchronization required for accessing the data.Object-oriented definition: a monitor is a synchronization object that is an instance of aspecial
monitor
class.
A monitor class defines private variables and public and private access methods.
-^
The variables of a monitor represent shared data.
-^
Threads communicate by calling monitor methods that access shared variables.
4.1.1 Mutual Exclusion At most one thread is allowed to execute inside a monitor at any time.-^
Mutual exclusion is automatically provided by the monitor’s implementation.
-^
If a thread calls a monitor method, but another thread is already executing inside themonitor, the calling thread must wait outside the monitor.
-^
A monitor has an entry
queue to hold the calling threads that are waiting to enter the
monitor. 4.1.2 Condition Variables and SC Signaling Condition synchronization is achieved using condition variables and operations
wait()
and
signal()
A condition variable
cv
is declared as
conditionVariable cv;
-^
Operation
cv.wait()
is used to block a thread (analogous to a
operation).
Operation
cv.signal()
unblocks a thread (analogous to a
operation).
A monitor has one entry queue plus one queue associated with each condition variable.For example, Listing 4.1 shows the structure of monitor class
boundedBuffer
. Class
boundedBuffer
inherits from class
monitor
. It has five data members, condition variables
named
notFull
and
notEmpty
, and monitor methods
deposit()
and
withdraw()
Fig. 4.2 is a graphical view of class
boundedBuffer
, which shows its entry queue and the
queues associated with condition variables
notFull
and
notEmpty
class boundedBuffer extends monitor {
public void deposit(…) { … }public int withdraw (…) { … }public boundedBuffer( ) { … }private int fullSlots = 0;
// # of full slots in the buffer
private int capacity = 0;
// capacity of the buffer
private int [] buffer = null;
// circular buffer of
ints
in
is index for next deposit,
out
is index for next withdrawal
private int in = 0, out = 0;// producer waits on
notFull
when the buffer is full
private conditionVariable notFull;// consumer waits on
notEmpty
when the buffer is empty
private conditionVariable notEmpty; }
Listing 4.1 Monitor class
boundedBuffer.^ deposit() {..}withdraw() {..}
entry queue
notFull notEmpty
Figure 4.2 Graphical view of monitor class
boundedBuffer
A thread that is executing inside a monitor method blocks itself on condition variable
cv
by executing cv.wait():^
releases mutual exclusion (to allow another thread to enter the monitor)
blocks the thread on the rear of the queue for
cv
A thread blocked on condition variable
cv
is awakened by cv.signal();
If there are no threads blocked on
cv
signal()
has no effect; otherwise,
signal()
awakens the thread at the front of the queue for
cv
For now, we will assume that the “signal-and-continue” (SC) discipline is used. Aftera thread executes an SC signal to awaken a waiting thread, the signaling threadcontinues executing in the monitor and the awakened thread is moved to the entryqueue;
the awakened thread does not reenter the monitor immediately
A: denotes the set of threads that have been awakened by
signal()
operations and are
waiting to reenter the monitor, S: denotes the set of signaling threads,C: denotes the set of threads that have called a monitor method but have not yet entered
the monitor. (The threads in sets A and C wait in the entry queue.) => The relative priority associated with these three sets of threads is S > C = A. cv.signalAll()
wakes up all the threads that are blocked on condition variable
cv
cv.empty() returns
true
if the queue for
cv
is empty, and
false
otherwise.
cv.length() returns the current length of the queue for
cv
Listing 4.3 shows a complete
boundedBuffer
monitor.
class
boundedBuffer
extends monitor {
private int fullSlots = 0; // number of full slots in the bufferprivate int capacity = 0;
// capacity of the buffer
private int[] buffer = null;
// circular buffer of ints
private int in = 0, out = 0;private conditionVariable notFull = new conditionVariable();private conditionVariable notEmpty = new conditionVariable();public boundedBuffer(int bufferCapacity ) {
capacity = bufferCapacity;buffer = new int[bufferCapacity];}public void deposit(int value) {while (fullSlots == capacity)
notFull.wait(); buffer[in] = value; in = (in + 1) % capacity;
++fullSlots;
notEmpty.signal();
//alternatively:if (fullSlots == 1) notEmpty.signal();
} public int withdraw() {
int value;while (fullSlots == 0)
notEmpty.wait(); value = buffer[out]; out = (out + 1) % capacity; --fullSlots;notFull.signal();
//alternatively:if (fullSlots == capacity–1) notFull.signal();
return value; } } Listing 4.3 Monitor class
boundedBuffer
4.2 Monitor-Based Solutions to Concurrent Programming Problems These solutions assume that condition variable queues are First-Come-First-Serve. 4.2.1 Simulating Counting Semaphores 4.2.1.1 Solution 1.
Listing 4.5 shows an SC monitor with methods
and
that
simulates a counting semaphore. In this implementation, a waiting thread may get stuckforever in the while-loop in method
assume that the value of
permits
is 0 when thread T1 calls
. Since the loop
condition (
permits == 0
) is true, T1 will block itself by executing a
wait
operation.
assume some other thread executes
and signals T1. Thread T1 will join the entry
queue behind threads that have called
) and are waiting to enter for the first time.
These other threads can enter the monitor and decrement
permits
before T1 has a
chance to reenter the monitor and examine its loop condition. If the value of
permits
is
0 when T1 eventually evaluates its loop condition, T1 will block itself again byissuing another
wait
operation.
class countingSemaphore1 extends monitor {
private int permits; // The value of
permits
is never negative.
private conditionVariable permitAvailable = new conditionVariable();public countingSemaphore1(int initialPermits) { permits = initialPermits;}public void P() {
while (permits == 0)
permitAvailable.wait(); --permits; } public void V() {
++permits;permitAvailable.signal(); } } Listing 4.5 Class
countingSemaphore
4.2.1.2 Solution 2
. The SC monitor in Listing 4.6 does not suffer from a starvation
problem. Threads that call
() cannot barge ahead of signaled threads and “steal” their
permits.Consider the scenario that we described in Solution 1:-^
If thread T1 calls
when the value of
permits
is 0, T1 will decrement
permits
to –
and block itself by executing a
wait
operation.
When some other thread executes
, it will increment
permits
to 0 and signal T1.
Threads ahead of T1 in the entry queue can enter the monitor and decrement
permits
before T1 is allowed to reenter the monitor.
-^
However, these threads will block themselves on the
wait
operation in P(), since
permits
will have a negative value.
Thread T1 will eventually be allowed to reenter the monitor. Since there are nostatements after the
wait
operation, T1 will complete its
operation.
^ In this solution, a waiting thread that is signaled is guaranteed to get a permit. class countingSemaphore2 extends monitor {
private int permits;
// The value of
permits
may be negative.
private conditionVariable permitAvailable = new conditionVariable();public countingSemaphore2(int initialPermits) { permits = initialPermits;}public void P() {
--permits;if (permits < 0)
permitAvailable.wait();
} public void V() {
++permits;permitAvailable.signal(); } } Listing 4.6 Class
countingSemaphore2.
4.2.2 Simulating Binary Semaphores In the SC monitor in Listing 4.7, Threads in
wait on condition
variable
allowP
while
threads in
wait on condition
variable
allowV
. Waiting threads may get stuck forever
in the while-loops in methods
and
class binarySemaphore extends monitor {
private int permits;private conditionVariable allowP = new conditionVariable();private conditionVariable allowV = new conditionVariable();public binarySemaphore(int initialPermits) { permits = initialPermits;}public void P() {
while (permits == 0)
allowP.wait(); permits = 0;allowV.signal(); } public void V() {
while (permits == 1)
allowV.wait(); permits = 1;allowP.signal(); } } Listing 4.7 Class
binarySemaphore
4.2.3 Dining Philosophers 4.2.3.1 Solution 1.
In the SC monitor in Listing 4.8, a philosopher picks up two
chopsticks only if both of them are available. Each philosopher has three possible states:thinking, hungry and eating:-^
A hungry philosopher can eat if her two neighbors are not eating.
-^
A philosopher blocks herself on a condition variable if she is hungry but unable to eat.
-^
After eating, a philosopher will unblock a hungry neighbor who is able to eat. This solution is deadlock-free, but not starvation-free, since a philosopher can starve ifone of its neighbors is always eatingHowever, the chance of a philosopher starving may be so highly unlikely that perhaps itcan be safely ignored? 4.2.3.2 Solution 2
. In Listing 4.9, each philosopher has an additional state called
“starving”:-^
A hungry philosopher is not allowed to eat if she has a starving neighbor, even if bothchopsticks are available.
-^
Two neighboring philosophers are not allowed to be starving at the same time. a hungry philosopher enters the “starving” state if she cannot eat and her twoneighbors are not starving. This solution avoids starvation. If there are five philosophers, then no more than fourphilosophers can eat before a given hungry philosopher is allowed to eat. However, somephilosophers may not be allowed to eat even when both chopsticks are available.Compared to Solution 1, this solution limits the maximum time that a philosopher can behungry, but it can also increase the average time that philosophers are hungry.
4.2.4 Readers and Writers Listing 4.10 is an SC monitor implementation of strategy R>W.1, which allowsconcurrent reading and gives readers a higher priority than writers (see Section 3.5.4.)Reader and writer threads have the following form:
r_gt_w.1 rw;Reader Threads:
Writer Threads:
rw.startRead();
rw.startWrite();
/* read shared data */
/* write to shared data */
rw.endRead();
rw.endWrite();
Writers are forced to wait in method
startWrite()
if any writers are writing or any readers
are reading or waiting.In method
endWrite()
, all the waiting readers are signaled since readers have priority.
However, one or more writers may enter method
startWrite()
before the signaled readers
reenter the monitor. Variable
signaledReaders
is used to prevent these barging writers
from writing when the signaled readers are waiting in the entry queue and no morereaders are waiting in
readerQ
Notice above that the shared data is read outside the monitor. This is necessary in order toallow concurrent reading.
class r_gt_w_1 extends monitor {
int readerCount = 0;
// number of active readers
boolean writing = false;
// true if a writer is writing
conditionVariable readerQ = new conditionVariable();conditionVariable writerQ = new conditionVariable();int signaledReaders = 0; // number of readers signaled in endWritepublic void startRead() {
if (writing) {
// readers must wait if a writer is writing
readerQ.wait();--signaledReaders;// another signaled reader has started reading } ++readerCount; } public void endRead() {
--readerCount;if (readerCount == 0 && signaledReaders==0)
// signal writer if no more readers are reading and the
signaledReaders
have read writerQ.signal(); } public void startWrite() {// the writer waits if another writer is writing, or a reader is reading or waiting,// or the writer is barging
while (readerCount > 0 || writing || !readerQ.empty() || signaledReaders>0)
writerQ.wait(); writing = true; } public void endWrite() {
writing = false;if (!readerQ.empty()) { // priority is given to waiting readers
signaledReaders = readerQ.length();readerQ.signalAll(); } else writerQ.signal(); } } Listing 4.10 Class
r_gt_w_
allows concurrent reading and gives readers a higher priority
than writers.
4.3 Monitors in Java Java’s wait, notify, and notifyAll operations combined with synchronized methods anduser-defined classes enables the construction of objects that have some of thecharacteristics of monitors.Adding synchronized to the methods of a Java class automatically provides mutualexclusion for threads accessing the data members of an instance of this class.However, if some or all of the methods are inadvertently not synchronized, a data racemay result. This enables the very types of bugs that monitors were designed to eliminate!There are no explicit condition variables in Java. When a thread executes a waitoperation, it can be viewed as waiting on a single, implicit condition variable associatedwith the object.Operations wait, notify, and notifyAll use SC signaling:^
A thread must hold an object’s lock before it can execute a wait, notify, or notifyAlloperation.
Thus,
these
operations
must
appear
in
a^
synchronized
method
or
synchronized block (see below); otherwise, an
IllegalMonitorStateException
is thrown.