Title: Chapter 7: Process Synchronization
1Chapter 7 Process Synchronization
2Contents
- Background
- The Critical-Section Problem
- Synchronization Hardware
- Semaphores
- Classical Problems of Synchronization
- Monitors
- Java Synchronization
- Synchronization in Solaris 2
- Synchronization in Windows NT
3Background
7.1
- Concurrent access to shared data may result in
data inconsistency. - Maintaining data consistency requires mechanisms
to ensure the orderly execution of cooperating
processes. - Shared-memory solution to bounded-butter problem
(Chapter 4) has a race condition on the class
data count
4Bounded Buffer
- public class BoundedBuffer
- public void enter(Object item)
- // producer calls this method
-
- public Object remove()
- // consumer calls this method
-
- // potential race condition on count
- private volatile int count
-
-
-
-
-
5enter() Method
- // producer calls this method
- public void enter(Object item)
- while (count BUFFER_SIZE)
- // do nothing
- // add an item to the buffer
- count
- bufferin item
- in (in 1) BUFFER_SIZE
6remove() Method
- // consumer calls this method
- public Object remove()
- Object item
- while (count 0)
- // do nothing
- // remove an item from the buffer
- --count
- item bufferout
- out (out 1) BUFFER_SIZE
- return item
-
7In machine language
- count register1 count register1 register1
1 count register1 - --count register2 count register2 register2
1 count register2
- The concurrent execution of the statements
count and count is equivalent to a sequential
execution where the lower-level statements are
interleaved in some arbitrary order.
8Race Condition
- T0 producer execute rigister1 count
register15 - T1 producer execute rigister1 rigister1
1 register16 - T2 consumer execute rigister2 count
register25 - T3 consumer execute rigister2 rigister2
1 register24 - T4 producer execute count rigister1 count
6 - T5 consumer execute count rigister2 count
4
Should be 5. Error!
To guard against the race condition, we need to
ensure that only one thread at a time can be
manipulating the variable count. To make such a
guarantee, we require some form of
synchronization of the threads.
9Critical-Section Problem
7.2
- Each thread has a segment of code, called a
critical section, in which the thread may be
changing common variables, updating a table,
writing a file, and so on. - When one thread is executing in its critical
section, no other thread is to be allowed to
execute in its critical sectionmutually
exclusive. - The critical-section problem is how to choose a
protocol that the threads can use to cooperate.
10Critical-Section Problem
7.2
- Each thread has a segment of code, called a
critical section, in which the thread may be
changing common variables, updating a table,
writing a file, and so on. - When one thread is executing in its critical
section, no other thread is to be allowed to
execute in its critical sectionmutually
exclusive. - The critical-section problem is how to choose a
protocol that the threads can use to cooperate.
( ) When one thread is executing in its
critical section, no other thread is to be
allowed to execute in its critical section, this
is called _________. (A) global data (B) common
method (C) mutually exclusive (D) constant
accessing (E) value assertion
Answer C
11Critical-Section Problem
- 1. Mutual Exclusion. If thread Ti is executing
in its critical section, then no other threads
can be executing in their critical sections. - 2. Progress. If no thread is executing in its
critical section and there exist some threads
that wish to enter their critical sections, then
only those threads that are not executing in
their noncritical section can participate in the
decision of which will enter its critical section
next, and this selection cannot be postponed
indefinitely. - 3. Bounded Waiting. A bound must exist on the
number of times that other threads are allowed to
enter their critical sections after a process has
made a request to enter its critical section and
before that request is granted. This bound
prevents starvation of any single thread.
12Critical-Section Problem
- 1. Mutual Exclusion. If thread Ti is executing
in its critical section, then no other threads
can be executing in their critical sections. - 2. Progress. If no thread is executing in its
critical section and there exist some threads
that wish to enter their critical sections, then
only those threads that are not executing in
their noncritical section can participate in the
decision of which will enter its critical section
next, and this selection cannot be postponed
indefinitely. - 3. Bounded Waiting. A bound must exist on the
number of times that other threads are allowed to
enter their critical sections after a process has
made a request to enter its critical section and
before that request is granted. This bound
prevents starvation of any single thread.
Short Answer Question A solution to the
critical-section problem must satisfy three
requirements mutual exclusive, progress, and
bounded waiting. Please explain the meaning of
these requirements.
13Critical-Section Problem
- 1. Mutual Exclusion. If thread Ti is executing
in its critical section, then no other threads
can be executing in their critical sections. - 2. Progress. If no thread is executing in its
critical section and there exist some threads
that wish to enter their critical sections, then
only those threads that are not executing in
their noncritical section can participate in the
decision of which will enter its critical section
next, and this selection cannot be postponed
indefinitely. - 3. Bounded Waiting. A bound must exist on the
number of times that other threads are allowed to
enter their critical sections after a process has
made a request to enter its critical section and
before that request is granted. This bound
prevents starvation of any single thread.
Multiple Choice Question ( ) Which of the
following is not one of the requirements for a
solution of critical-section problem? (A)
progress (B) loopless (C) mutual exclusive (D)
bounded waiting
Answer B
14Critical-Section Problem
- We can make no assumption concerning the
relative speed of the n threads. - The solutions should not rely on any assumptions
concerning the hardware instructions. - However, the basic machine-language instructions
(the primitive instructions such as load, store,
and test) are executed atomically.
15Critical-Section Problem
- We can make no assumption concerning the
relative speed of the n threads. - The solutions should not rely on any assumptions
concerning the hardware instructions. - However, the basic machine-language instructions
(the primitive instructions such as load, store,
and test) are executed atomically.
True-False Question ( ) When solving critical
section problems, we should make proper
assumption concerning the relative speed of the
threads.
Answer
16Two-Tasks Solutions
7.3
- Each thread is implemented using the worker
class. (Fig 7.1) - A call to the methods criticalSection() and
nonCriticalSection() represents the places where
each thread performs its critical and noncritical
sections. - Prior to calling its critical section, each
thread will call the method enteringCriticalSectio
n(). - A thread will not return from enteringCriticalSect
ion() until it is able to enter its critical
section.
17Worker Thread
- public class Worker extends Thread
- public Worker(String n, int i, MutualExclusion
s) - name n
- id i
- shared s
-
- public void run() / see next slide /
-
- private String name
- private int id
- private MutualExclusion shared
18run() Method of Worker Thread
Codes in critical section
- public void run()
- while (true)
- shared.enteringCriticalSection(id)
- system.out.println(name is in critical
section) - MutualExclusion.criticalSection()
- shared.leavingCriticalSection(id)
- System.out.println(name is out of critical
section) - MutualExclusion.noncriticalSection()
-
Codes out of critical section
19MutualExclusion Abstract Class
This abstract class will serve as a template for
the following three algorithms
- public abstract class MutualExclusion
- public static void criticalSection()
- // simulate the critical section
-
- public static void nonCriticalSection()
- // simulate the non-critical section
-
- public abstract void enteringCriticalSection(int
t) - public abstract void leavingCriticalSection(int
t) - public static final int TURN_0 0
- public static final int TURN_1 1
20Testing Each Algorithm
- public class TestAlgorithm
-
- public static void main(String args)
- MutualExclusion alg new Algorithm_1()
-
- Worker first new Worker("Runner 0", 0,
alg) - Worker second new Worker("Runner 1", 1,
alg) -
- first.start()
- second.start()
-
Creating the two threads and used to test each
algorithm
21Algorithm 1
7.3.1
Keeps the thread in the Runnable state, but also
allows the JVM to select another Runnable thread
of equal priority to run.
- public class Algorithm_1 extends MutualExclusion
- public Algorithm_1()
- turn TURN_0
-
- public void enteringCriticalSection(int t)
- while (turn ! t)
- Thread.yield()
-
- public void leavingCriticalSection(int t)
- turn 1 - t
-
- private volatile int turn
22Algorithm 1
- Ensures that only one thread at a time can be in
its critical section. - However, does not satisfy the progress
requirement, since it requires strict alternation
of threads in the execution of their critical
section.
23Algorithm 2
- public class Algorithm_2 extends MutualExclusion
- public Algorithm_2()
- flag0 false
- flag1 false
-
- public void enteringCriticalSection(int t)
- int other 1 - t
- flagt true
- while (flagother true)
- Thread.yield()
-
- public void leavingCriticalSection(int t)
- flagt false
-
- private volatile boolean flag new
boolean2
24Algorithm 2
- public class Algorithm_2 extends MutualExclusion
- public Algorithm_2()
- flag0 false
- flag1 false
-
- public void enteringCriticalSection(int t)
- int other 1 - t
- flagt true
- while (flagother true)
- Thread.yield()
-
- public void leavingCriticalSection(int t)
- flagt false
-
- private volatile boolean flag new
boolean2
Short Answer Question Examine the
algorithm on the right for solving two-tasks
critical-section problem. What this algorithm has
achieved and what kind of problem this algorithm
is encountered, if any ?
25Algorithm 2
- The mutual-exclusion requirement is satisfied.
- Unfortunately, the progress requirement is still
not met. - When both threads perform the while statement,
they will loop forever as the value of flag for
the other thread is true.
26Algorithm 3
- public class Algorithm_3 extends MutualExclusion
- public Algorithm_3()
- flag0 false
- flag1 false
- turn TURN_0
-
- public void enteringCriticalSection(int t) /
see next slides / - public void leavingCriticalSection(int t)
/ see next slides / - private volatile int turn
- private volatile boolean flag new
boolean2
27Algorithm 3
- public void enteringCriticalSection(int t)
- int other 1 - t
- flagt true
- turn other
- while ( (flagother true) (turn other)
) - Thread.yield()
-
- public void leavingCriticalSection(int t)
flagt false -
28Algorithm 3
- Correct solution to the critical-section problem.
- If both threads try to enter at the same time,
turn is set to both I and j at roughly the same
time. - Only one of these assignments lasts the other
will occur, but will be overwritten immediately. - The eventual value of turn decides which of the
two threads is allowed to enter its critical
section first.
29Synchronization Hardware
7.4
- Hardware instructions can be used effectively in
solving critical-section problem. - It allows as either to test and modify the
content of a word, or to swap the contents of two
words, atomically --- as one uninterruptible unit.
30Synchronization Hardware
- public class HardwareData
- public HardwareData(boolean v)
- data v
-
- public boolean get()
- return data
-
- public void set(boolean v)
- data v
-
- private boolean data
31Test-and-Set Instruction (in Java)
- public class HardwareSolution
-
- public static boolean testAndSet(HardwareData
target) - HardwareData temp new HardwareData(target.get(
)) - target.set(true)
- return temp.get()
-
32Test-and-Set Instruction (in Java)
True-False Question ( ) The value of the lock
returned by the test-and set instruction is the
value after the instruction is applied onto the
lock.
- public class HardwareSolution
-
- public static boolean testAndSet(HardwareData
target) - HardwareData temp new HardwareData(target.get(
)) - target.set(true)
- return temp.get()
-
Answer
33Thread using Test-and-Set
- HardwareData lock new HardwareData(false)
- while (true)
- while (HardwareSolution.testAndSet(lock))
- Thread.yield( ) // do nothing
- criticalSection( )
- lock.set(false)
- nonCriticalSection( )
34Thread using Test-and-Set
Multiple Choices Question ( ) When calling a
test-and-set instruction, a ______ must be
provided as its parameter.(a) semaphore (b)
integer (c) constant (d) lock
- HardwareData lock new HardwareData(false)
- while (true)
- while (HardwareSolution.testAndSet(lock))
- Thread.yield( ) // do nothing
- criticalSection( )
- lock.set(false)
- nonCriticalSection( )
Answer d
35Thread using Test-and-Set
True-False Question ( ) When the value
returned by the test-and-set instruction is
false, it means that the locking is not
successful.
- HardwareData lock new HardwareData(false)
- while (true)
- while (HardwareSolution.testAndSet(lock))
- Thread.yield( ) // do nothing
- criticalSection( )
- lock.set(false)
- nonCriticalSection( )
Answer x
36Swap instruction
- Also executed atomically.
- public static void swap(HardwareData a,
HardwareData b) - HardwareData temp new HardwareData(a.get())
- a.set(b.get())
- b.set(temp.get())
37Thread using Swap
- HardwareData lock new HardwareData(false)
- HardwareData key new HardwareData(true)
- while (true)
- key.set(true)
- do
- HardwareSolution.swap(lock,key)
- while (key.get() true)
- criticalSection( )
- lock.set(false)
- nonCriticalSection( )
38Thread using Swap
Multiple Choices Question ( ) The value of
the key used to switch with the lock must be set
to ______ before calling the swap method.(a)
constant (b) false (c) true (d) integer
- HardwareData lock new HardwareData(false)
- HardwareData key new HardwareData(true)
- while (true)
- key.set(true)
- do
- HardwareSolution.swap(lock,key)
- while (key.get() true)
- criticalSection( )
- lock.set(false)
- nonCriticalSection( )
Answer c
39Semaphore
7.5
- Previous solutions (7.3) are not easy to
generalize to more complex problems. - Semaphores can be implemented as synchronization
tool that does not require busy waiting. - A semaphore S is an integer variable that can
only be accessed via two indivisible (atomic)
operations P and V. - P(S)
- while S ? 0
- // no-op S--
-
These are classical definition of P and V, they
require busy waiting.
V(S) S
40Semaphore as General Synchronization Tool
7.5.1
- Semaphore S // initialized to 1
- P(S)
- CriticalSection()
- V(S)
- The value of a counting semaphore can range over
an unrestricted domain. The value of a binary
semaphore can range only between 0 and 1.
41Semaphore Eliminating Busy-Waiting
- The main disadvantage of previous solutions they
all require busy waitinga problem in single CPU,
multiprogramming system. - Busy waiting wastes CPU cycles that some other
process might be able to use productively. This
type of semaphore is also called a spinlock.
- Spinlocks are useful in multiprocessor systems.
The - advantage of a spinlock is that no context
switch is required - when a process must wait on a lock (context
switch - may take considerable time).
- Spinlocks are useful when locks are expected to
be held for - short times.
42Semaphore Eliminating Busy-Waiting
- The main disadvantage of previous solutions they
all require busy waitinga problem in single CPU,
multiprogramming system. - Busy waiting wastes CPU cycles that some other
process might be able to use productively. This
type of semaphore is also called a spinlock.
- To overcome the need for busy waiting, the
definition of P and V are modified.
43Semaphore Eliminating Busy-Waiting
Short Answer Question Although spinlocks
waist CPU time with busy waiting, they are still
useful in some systems. What are the advantage of
spinlocks and in which situation they are
considered useful?
- The main disadvantage of previous solutions they
all require busy waitinga problem in single CPU,
multiprogramming system. - Busy waiting wastes CPU cycles that some other
process might be able to use productively. This
type of semaphore is also called a spinlock.
- To overcome the need for busy waiting, the
definition of P and V are modified.
44Semaphore Eliminating Busy-Waiting
- P(S)
- value--
- if (value lt 0)
- add this process to list
- block
-
-
- V(S)
- value
- if (value lt 0)
- remove a process P from list
- wakeup(P)
-
-
The block operation places a process into a
waiting queue associated with the semaphore, and
the state of the process is switched to the
waiting state.
A process that is blocked, waiting on S, should
be restarted when some other process execute a V
operation.
When the process is restarted by the wakeup
operation, the process is changed from the
waiting state to the ready state.
45Synchronization Using Semaphores
- public class FirstSemaphore
- public static void main(String args)
- Semaphore sem new Semaphore(1)
- Worker bees new Worker5
-
- for (int i 0 i lt 5 i)
- beesi new Worker(sem, "Worker "
- (new Integer(i)).toString() )
-
- for (int i 0 i lt 5 i)
- beesi.start()
-
46Worker Thread
- public class Worker extends Thread
- public Worker(Semaphore s, String n)
- name n sem s
- public void run()
- while (true)
- sem.P( )
- // in critical section
- sem.V( )
- // out of critical section
-
-
- private Semaphore sem
- private String name
47Deadlock and Starvation
the execution of a V operation
- 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
- P(S) P(Q)
- P(Q) P(S)
- ? ?
- V(S) V(Q)
- V(Q) V(S)
- Starvation indefinite blocking. A process may
never be removed from the semaphore queue in
which it is suspended.
48Deadlock and Starvation
the execution of a V operation
- 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
- P(S) P(Q)
- P(Q) P(S)
- ? ?
- V(S) V(Q)
- V(Q) V(S)
- Starvation indefinite blocking. A process may
never be removed from the semaphore queue in
which it is suspended.
True-False Question ( ) A deadlock can only
happen in between two threads.
Answer
49Classical Problems of Synchronization
7.6
- Bounded-Buffer Problem
- Readers and Writers Problem
- Dining-Philosophers Problem
50Bounded-Buffer Problem
7.6.1
- public class BoundedBuffer
- public BoundedBuffer() / see next slides /
- public void enter() / see next slides /
- public Object remove() / see next slides /
-
- private static final int BUFFER_SIZE 2
- private Semaphore mutex
- private Semaphore empty
- private Semaphore full
- private int in, out
- private Object buffer
-
-
51Bounded Buffer Constructor
- public BoundedBuffer()
- // buffer is initially empty
- count 0
- in 0
- out 0
- buffer new ObjectBUFFER_SIZE
- mutex new Semaphore(1)
- empty new Semaphore(BUFFER_SIZE)
- full new Semaphore(0)
-
52enter() Method
- public void enter(Object item)
- empty.P()
- mutex.P()
-
- // add an item to the buffer
- bufferin item
- in (in 1) BUFFER_SIZE
- mutex.V()
- full.V()
53enter() Method
Multiple Choices Question ( ) Consider
following program for the enter() method of
bounded-buffer problem. Which instruction is
missing from the blank?(a) empty.V() (b)
mutex.V() (c) full.P() (d) empty.P() public
void enter(Object item) empty.P()
mutex.P() // add an item to the buffer
bufferin item in (in 1)
BUFFER_SIZE __________ full.V()
- public void enter(Object item)
- empty.P()
- mutex.P()
-
- // add an item to the buffer
- bufferin item
- in (in 1) BUFFER_SIZE
- mutex.V()
- full.V()
Answer b
54remove() Method
- public Object remove()
- full.P()
- mutex.P()
- // remove an item from the buffer
- Object item bufferout
- out (out 1) BUFFER_SIZE
- mutex.V()
- empty.V()
- return item
-
55Readers-Writers Problem
7.6.2
- The readers-writers problem has several
variations, all involving priorities. - first no reader will be kept waiting unless a
writer has already obtained permission to use the
shared database.
No reader should wait for other readers to finish
simply because a writer is waiting.
Starvation writers
56Readers-Writers Problem
- second once a writer is ready, that writer
performs its write as soon as possible. If a
writer is waiting to access the object, no new
readers may start reading.
Starvation readers
- Here we present the first solution.
57Readers-Writers Problem
- second once a writer is ready, that writer
performs its write as soon as possible. If a
writer is waiting to access the object, no new
readers may start reading.
True-False Question ( ) If a reader will be
kept waiting only if a writer is currently
working on the database, the starvation may
happen on the reader.
Starvation readers
Answer
- Here we present the first solution.
58Readers-Writers Problem Reader
- public class Reader extends Thread
- public Reader(Database db)
- server db
-
- public void run()
- int c
- while (true)
- c server.startRead()
- // now reading the database
- c server.endRead()
-
-
- private Database server
59Readers-Writers Problem Writer
- public class Writer extends Thread
- public Writer(Database db)
- server db
-
- public void run()
- while (true)
- server.startWrite()
- // now writing the database
- server.endWrite()
-
-
- private Database server
-
60Readers-Writers Problem (cont)
- public class Database
-
- public Database()
- readerCount 0
- mutex new Semaphore(1)
- db new Semaphore(1)
-
- public int startRead() / see next slides /
- public int endRead() / see next slides /
- public void startWrite() / see next slides /
- public void endWrite() / see next slides
/ - private int readerCount // number of active
readers - Semaphore mutex // controls access to
readerCount - Semaphore db // controls access to
the database -
-
-
61startRead() Method
- public int startRead()
- mutex.P()
- readerCount
- // if I am the first reader tell all others
- // that the database is being read
- if (readerCount 1)
- db.P()
-
- mutex.V()
- return readerCount
-
62endRead() Method
- public int endRead()
- mutex.P()
- --readerCount
- // if I am the last reader tell all others
- // that the database is no longer being
read - if (readerCount 0)
- db.V()
-
- mutex.V()
- return readerCount
-
63endRead() Method
- public int endRead()
- mutex.P()
- --readerCount
- // if I am the last reader tell all others
- // that the database is no longer being
read - if (readerCount 0)
- db.V()
-
- mutex.V()
- return readerCount
-
True-False Question ( ) Although there are
many readers working on the database with the
startRead() and endRead() method, the semaphore
db will be acquired (P operation) and released (V
operation) by the same reader.
Answer
64Writer Methods
- public void startWrite()
- db.P()
-
- public void endWrite()
- db.V()
-
65Writer Methods
Short Answer Question Please explain
why the startWrite() method does not need to use
the semaphore mutex as startRead() does.
- public void startWrite()
- db.P()
-
- public void endWrite()
- db.V()
-
66Dining-Philosophers Problem
7.6.3
- A classic synchronization problem because it is
an example of a large class of concurrency-control
problems.
67Dining-Philosophers Problem
- Simple solution represent each chopstick by a
semaphore. Get the chopstick PRelease the
chopstick V - Shared data
- Semaphore chopStick new
Semaphore5
68Dining-Philosophers Problem
- Philosopher i
- while (true)
- // get left chopstick
- chopSticki.P()
- // get right chopstick
- chopStick(i 1) 5.P()
- eating()
-
- //return left chopstick
- chopSticki.V()
- // return right chopstick
- chopStick(i 1) 5.V()
-
- thinking()
-
Deadlock when all five philosophers get her left
chopstick at the same time
69Dining-Philosophers Problem
- Philosopher i
- while (true)
- // get left chopstick
- chopSticki.P()
- // get right chopstick
- chopStick(i 1) 5.P()
- eating()
-
- //return left chopstick
- chopSticki.V()
- // return right chopstick
- chopStick(i 1) 5.V()
-
- thinking()
-
Multiple Choices Question ( ) In
Dining-Philosophers Problem, if all philosophers
get their right chopstick at the same time, what
will happen?(a) starvation (b) deadlock (c)
blocking (d) synchronization (e) mutual
exclusioncc
Deadlock when all five philosophers get her left
chopstick at the same time
Answer b
70Dining-Philosophers Problem
- Preventing deadlock by placing restrictions
- Allow at most four philosophers to be sitting
simultaneously at the table. - Allow a philosopher to pick up only if both
chopsticks are available. - Use an asymmetric solution(for example, an odd
philosopher picks up left then right, whereas an
even philosopher picks up her right chopstick and
then her left.) - (Section 7.7 presents a solution to the
dining-philosophers
problem.)
71Monitors
7.6.4
- Although semaphores provide a convenient and
effective mechanism for process synchronization,
their incorrect use can still result in timing
errors that are difficult to detect. - Examples
A process omits the mutex.P(), or the mutex.V(),
or both Either mutual exclusion is violated or
a deadlock will occur.
mutex.P() criticalSection() mutex.P() A
deadlock will occur.
mutex.V() criticalSection() mutex.P() Several
processes may be executing in their critical
section simultaneously.
72Monitors
7.6.4
- Although semaphores provide a convenient and
effective mechanism for process synchronization,
their incorrect use can still result in timing
errors that are difficult to detect. - Examples
Multiple Choices Question ( ) What kind of
problem can happen if more than one thread work
on a semaphore in the following sequence?
mutex.V() criticalSection()
mutex.P()(a) starvation (b) deadlock (c)
blocking (d) not synchronizing (e) violate
mutual exclusion
A process omits the mutex.P(), or the mutex.V(),
or both Either mutual exclusion is violated or
a deadlock will occur.
mutex.P() criticalSection() mutex.P() A
deadlock will occur.
mutex.V() criticalSection() mutex.P() Several
processes may be executing in their critical
section simultaneously.
Answer e
73Monitors
7.7
- A monitor is a high-level abstraction that
provides thread safety. - A monitor presents a set of programmer-defined
operations that are provided mutual exclusion
within the monitor. - Syntax of a monitor
- monitor monitor-name
-
- // variable declarations
- public entry p1()
-
-
- public entry p2()
-
-
-
74Condition Variables
- Encapsulation limits access to the local
variables by only the local procedures. - The monitor construct prohibits concurrent access
to all procedures defined within the monitor. - Only one thread may be active within the monitor
at a time. - Synchronization is built into the monitor type,
the programmer does not need to code it
explicitly. - Special operations wait and signal can be invoked
on the variables of type condition.
condition x, y - A thread that invokes x.wait is suspended until
another thread invokes x.signal
75Condition Variables
- Encapsulation limits access to the local
variables by only the local procedures. - The monitor construct prohibits concurrent access
to all procedures defined within the monitor. - Only one thread may be active within the monitor
at a time. - Synchronization is built into the monitor type,
the programmer does not need to code it
explicitly. - Special operations wait and signal can be invoked
on the variables of type condition.
condition x, y - A thread that invokes x.wait is suspended until
another thread invokes x.signal
True-False Question ( ) Although there maybe
several threads inside the monitor at the same
time, there can only be one thread with the state
of active at a time.
Answer ?
76Monitor with condition variables
77Solution to Dining Philosophers
With this, philosopher i can delay herself when
she is hungry, but is unable to obtain the
chopsticks she needs.
- monitor diningPhilosophers
- int state new int5
- static final int THINKING 0
- static final int HUNGRY 1
- static final int EATING 2
- condition self new condition5
- public diningPhilosophers
- for (int i 0 i lt 5 i)
- statei THINKING
-
- public entry pickUp(int i) / see next slides
/ - public entry putDown(int i) / see next slides
/ - private test(int i) / see next slides /
78pickUp() Procedure
Each philosopher, before starting to eat, must
invoke the operation pickup().
- public entry pickUp(int i)
- statei HUNGRY
- test(i)
- if (statei ! EATING)
- selfi.wait
May result in the suspension of the philosopher
thread.
79test() Procedure
- private test(int i)
- if ( (state(i 4) 5 ! EATING)
- (statei HUNGRY)
- (state(i 1) 5 ! EATING) )
- statei EATING
- selfi.signal
-
-
Release selfi so that the thread can proceed.
80putDown() Procedure
- public entry putDown(int i)
- statei THINKING
- // test left and right neighbors
- test((i 4) 5)
- test((i 1) 5)
Ok, I have finished eating, now you guys go try
it!
81Solution to Dining Philosophers
- Sequence of invoke dp.pickUp(i) eat() dp.putD
own(i) - This is a deadlock free solution but starvation
is still possible.
82Java Synchronization
7.8
- An application that ensures data consistency even
when being concurrently accessed by multiple
threads is said to be thread safe. - In Section 7.5.2, using P and V semaphore
operation for busy waiting was introduced. An
alternative is allowing a process to block
itself.
In Java, have a thread call the Thread.yield()
method can accomplish such blocking.
83Busy Waiting
7.8.1.1
- The yield() method makes more effective use of
the CPU than busy waiting does. - However, using either busy waiting or yielding
could potentially lead to a deadlock. - Example (Recall Section 7.3.1) (page 21 in this
.ppt file) - JVM ensure higher priority thread in the
Runnable state will run before lower priority
one. If the producer has higher priority than
consumer and the buffer is full the producer
enter the while loop and wait (or yield) to
another Runnable thread with equal priority while
waiting for count to be decremented to less than
BUFFER_SIZE. But the consumer has lower priority
than producer and will never be scheduled by the
JVM to run deadlocked.
- The producer is waiting for the consumer to free
buffer space and the consumer is waiting to be
scheduled by the JVM. - We need a better solution.
84Race Condition
- Java prevent race condition by lock ownership.
- Every object has a lock associated with it.
- Calling a synchronized method requires owning
the lock. - If a calling thread does not own the lock
(another thread already owns it), the calling
thread is placed in the entry set for the
objects lock. - The entry set represents the set of threads
waiting for the lock to become available.
85Race Condition
- Java prevent race condition by lock ownership.
- Every object has a lock associated with it.
- Calling a synchronized method requires owning
the lock. - If a calling thread does not own the lock
(another thread already owns it), the calling
thread is placed in the entry set for the
objects lock. - The entry set represents the set of threads
waiting for the lock to become available.
Multiple Choices Question ( ) In Java, if a
calling thread cannot own a lock because another
thread already owns it, the calling thread is
placed in the _______ for the objects lock and
wait.(a) queue (b) wait array (c) monitor (d)
entry set (e) blocking room
Answer d
86Entry Set
- If the lock is available when a synchronized
method is called, the calling thread becomes the
owner of the objects lock and it can enter the
method. - The lock is released when a thread exits the
synchronized method. - If the entry set for the lock is not empty when
the lock is released, the JVM selects an
arbitrary thread from this set as the new owner
of the lock.
87Synchronized enter() Method
- public synchronized void enter(Object item)
- while (count BUFFER_SIZE)
- Thread.yield()
- count
- bufferin item
- in (in 1) BUFFER_SIZE
88Synchronized remove() Method
- public synchronized Object remove()
- Object item
- while (count 0)
- Thread.yield()
- --count
- item bufferout
- out (out 1) BUFFER_SIZE
- return item
89Wait set
- synchronized method prevents race condition,
however, the presence of yield() loop has led to
another type of possible deadlock When the
buffer is full and the consumer is sleeping, the
producer calls the enter() method will own the
lock and perform yield(). And, when the consumer
awakens and tries to call the remove(), it will
be blocked. - Wait set with wait() and notify() is introduced.
90The wait() Method
- When a thread calls wait(), the following occurs
- - the thread releases the object lock.
- - thread state is set to Blocked.
- - thread is placed in the wait set for the
object.
91Entry and Wait Sets
92The notify() Method
- When a thread calls notify(), the following
occurs - - Picks an arbitrary thread T from the wait set.
- - Moves T to the entry set.
- - Sets T from Blocked to Runnable.
- T can now compete for the objects lock again.
93enter() with wait/notify Methods
- public synchronized void enter(Object item)
- while (count BUFFER_SIZE)
- try
- wait()
-
- catch (InterruptedException e)
-
- count
- bufferin item
- in (in 1) BUFFER_SIZE
- notify()
94remove() with wait/notify Methods
- public synchronized Object remove()
- Object item
- while (count 0)
- try
- wait()
-
- catch (InterruptedException e)
- --count
- item bufferout
- out (out 1) BUFFER_SIZE
- notify()
- return item
95The Readers-Writers Problem--Solved with Java
Synchronization
7.8.3
- public class Database
- public Database()
- readerCount 0
- dbReading false
- dbWriting false
-
- public synchronized int startRead() / see
next slides / - public synchronized int endRead() / see
next slides / - public synchronized void startWrite() / see
next slides / - public synchronized void endWrite() / see
next slides / - private int readerCount
- private boolean dbReading
- private boolean dbWriting
-
-
-
96startRead() Method
- public synchronized int startRead()
- while (dbWriting true)
- try
- wait()
-
- catch (InterruptedException e)
- readerCount
- if (readerCount 1)
- dbReading true
- return readerCount
If I am the first reader tell all others that the
database is being read
97endRead() Method
- public synchronized int endRead()
- --readerCount
- if (readerCount 0)
- db.notifyAll()
- return readerCount
-
If I am the last reader tell all others that the
database is no longer being read
98Writer Methods
- public void startWrite()
- while (dbReading true dbWriting
true) - try
- wait()
-
- catch (InterruptedException e)
- dbWriting true
-
- public void endWrite()
- dbWriting false
- notifyAll()
-
-
Once there are either no readers or writers
indicate that the database is being written
99Multiple Notifications
7.8.4
- notify() selects an arbitrary thread from the
wait set. This may not be the thread that you
want to be selected. - Java does not allow you to specify the thread to
be selected. - notifyAll() removes ALL threads from the wait set
and places them in the entry set. This allows the
threads to decide among themselves who should
proceed next. - notifyAll() is a conservative strategy that works
best when multiple threads may be in the wait set.
100Block Synchronization
7.8.5
- In Java, blocks of code rather than entire
methods may be declared as synchronized. public
void someMethod() synchronized(this) //
remainder of the method - This yields a lock scope that is typically
smaller than a synchronized method. - The amount of time between when a lock is
assigned and when it is released is defined as
the scope of the lock.
101Block Synchronization
7.8.5
Multiple Choices Question ( )The amount of
time between when a lock is assigned and when it
is released is defined as the _______ of the
lock.(a) length (b) entry point (c) scope
(d) size (e) duration
- In Java, blocks of code rather than entire
methods may be declared as synchronized. public
void someMethod() synchronized(this) //
remainder of the method - This yields a lock scope that is typically
smaller than a synchronized method. - The amount of time between when a lock is
assigned and when it is released is defined as
the scope of the lock.
Answer C
102Block Synchronization
7.8.5
Multiple Choices Question ( ) In Java, the
scope of the lock can be defined within the size
of a(a) method (b) procedure (c) block (d)
message (e) entry set
- In Java, blocks of code rather than entire
methods may be declared as synchronized. public
void someMethod() synchronized(this) //
remainder of the method - This yields a lock scope that is typically
smaller than a synchronized method. - The amount of time between when a lock is
assigned and when it is released is defined as
the scope of the lock.
Answer C
103Block Synchronization (cont)
- Object mutexLock new Object()
- . . .
- public void someMethod()
- // non-critical section
- synchronized(mutexLock)
- try mutexLock.wait()
-
- catch (InterruptedException ie)
-
- synchronized(mutexLock)
- mutexLock.notify()
-
-
104Java Semaphores
7.8.6
- Java does not provide a semaphore, but a basic
semaphore can be constructed using Java
synchronization mechanism.
105Semaphore Class
- public class Semaphore
- public Semaphore()
- value 0
-
- public Semaphore(int v)
- value v
-
- public synchronized void P() / see next
slide / - public synchronized void V() / see next slide
/ - private int value
106P and V Operations
- public synchronized void P()
- while (value lt 0)
- try
- wait()
-
- catch (InterruptedException e)
-
- value --
-
- public synchronized void V()
- value
-
- notify()
-
107Synchronization Rules
7.8.7
- A thread that owns the lock for an object can
enter another synchronized method (or block) for
the same object. - A thread can nest synchronized method invocations
for different objects. Thus a thread can
simultaneously own the lock for several different
objects. - If a method is not declared as synchronized, then
it can be invoked regardless of lock ownership,
even while another synchronized method for the
same object is executing.
108Synchronization Rules
7.8.7
True-False Question ( ) Although a thread
cannot own many locks at the same time, it can
invoke many synchronized methods within a lock at
the same time.
- A thread that owns the lock for an object can
enter another synchronized method (or block) for
the same object. - A thread can nest synchronized method invocations
for different objects. Thus a thread can
simultaneously own the lock for several different
objects. - If a method is not declared as synchronized, then
it can be invoked regardless of lock ownership,
even while another synchronized method for the
same object is executing.
Answer
109Java Monitors (?)
7.8.8
110OS Synchronization
7.9
- Synchronization in Solaris 2 Provides
- - adaptive mutex
- - condition variables
- - semaphores
- - reader-writer locks
111Adaptive Mutex
- An adaptive mutex protects access to every
critical data item. It starts as a standard
semaphore implemented as a spinlock. - If the data are locked (in use), the adaptive
mutex does one of two things - If the lock is held by a thread that is currently
running on another CPU, the thread spins while
waiting for the lock to become available. - If the thread holding the lock is not currently
in run state, the thread blocks and go to sleep
until the lock being released.
The thread holding the data is likely to end soon.
Put to sleep for avoiding the spinning when the
lock will not be freed reasonably quickly.
112Adaptive Mutex
Multiple Choices Question ( ) Different
operations may be adopted by the adaptive mutex
mechanism when a thread is requesting a locked
data. The decision is made by the status of(a)
located memories (b) relative CPU speed (c) the
thread holding the lock (d) the type of
monitor entries
- An adaptive mutex protects access to every
critical data item. It starts as a standard
semaphore implemented as a spinlock. - If the data are locked (in use), the adaptive
mutex does one of two things - If the lock is held by a thread that is currently
running on another CPU, the thread spins while
waiting for the lock to become available. - If the thread holding the lock is not currently
in run state, the thread blocks and go to sleep
until the lock being released.
Put to sleep for avoiding the spinning when the
lcok will not be freed reasonably quickly.
Answer C
113Adaptive Mutex
- Adaptive mutex only protect those data that are
accessed by short code segments where a lock will
be held for less than a few hundred instructions.
- For longer code segments, condition variables and
semaphores are used. - If the desired lock is already held, the thread
issues a wait and sleep. - The cost of putting a thread to sleep and waking
it is less than the cost of wasting several
hundred instructions waiting in a spinlock.
If the code segment is longer than that, spin
waiting will be exceedingly inefficient.
114Readers-Writers Lock
- The readers-writers locks are used to protect
data that are accessed frequently, but usually
only in a read-only manner. - In these circumstances, readers-writers locks are
more efficient than semaphores. - Expensive to implement, so again they are used on
only long sections of code.
THINK
115Windows NT Synchronization
- Windows NT Provides
- - mutex
- - critical sections
- - semaphores
- - event objects
116The End