Guarded Methods and Waiting

Guarded Methods and Waiting
SPL/2010
1
Reminder!
●
Concurrency problem: asynchronous
modifications to object states lead to failure
of thread computation (pre-condition is not
met)
SPL/2010
2
Overview
●
Techniques to deal with potential failures
●
●
●
check all invariants and preconditions before
performing action
refuse to perform actions unless they can ensure
that these actions will succeed
exceptions, exception handling code
SPL/2010
3
SPL/2010
4
Policies for failed preconditions/invariants
●
●
●
Balking. throw exception if precondition fails.
try, and if you cannot succeed, fail fast
Guarded suspension. suspend method invocation
(and thread) until precondition becomes true.
Time-outs. between balking and suspension.
Bounded wait for precondition to become true.
SPL/2010
5
Today
●
guarded suspension
●
general suspension mechanisms in Java RTE
SPL/2010
6
Guarded suspension and time-outs in
concurrent software
●
abstract queue supports add() get() size()
SPL/2010
7
Guards = special conditionals
●
Conditionals in sequential programs:
●
if statement check condition on method entry
●
if false - no wait - can never become true
SPL/2010
8
Queue impl.
Balking
SPL/2010
9
Guarded suspension
●
asynchronous state changes can happen
●
precondition may hold in the future
●
wait until precondition holds
●
guard asserts that another thread will
make required state changes…
●
Time-outs - soft guards - balking policy if wait
for too long
SPL/2010
10
SPL/2010
11
Java Mechanics for Guarded Suspension
●
Wait/Notify constructs - simple, mechanism
for suspension in multi-threaded context
1.
mechanism semantics
2.
higher level constructs to simplify usability
SPL/2010
12
wait()
●
threads may wait() until some other thread
wakes them up
●
●
●
each object has a wait set - similar to locks
entities possessing locks and wait sets are
called monitors
maintained internally by the JVM
●
set holds threads blocked by wait on object
●
until notifications are invoked or waits released
SPL/2010
13
notify()
●
●
threads enter wait queue of object o by
invoking the wait() of o.
thread wakeups threads from queue
of o by: o.notify()/o.notifyAll()
SPL/2010
14
wait/notify cycle
●
●
●
o.wait() - wait invocation
●
current thread calling wait() is blocked.
●
JVM places thread in wait set of o.
o.notify() - notify invocation
●
arbitrarily thread T is removed from o’s wait set
●
T is resumed from the point of wait().
o.notifyAll()
●
like notify except for all threads in o’s wait set
SPL/2010
15
Interrupting Threads
●
Special JVM exception to threads:
●
●
thread may need to stop waiting for a notify()
(example when program needs to exit)
InterruptedException – wait() method exits
immediately
SPL/2010
16
Handle InterruptedException
?
SPL/2010
17
Back to queue
●
Producer-Consumer design pattern
●
●
●
Producer produces objects /Consumer needs
process
decouple processes that produce and consume
data at different rates
queue data in producer loop / process in
consumer loop at own pace
SPL/2010
18
SPL/2010
19
●
video player example:
●
●
●
Producer read the file from disk and give chunks
of data to Consumer – add()
Consumer decodes and play – take()
Guard add() / take() methods, such that all
preconditions are respected
–
SPL/2010
wait() until the preconditions hold.
20
Producer-Consumer Queue
SPL/2010
21
SPL/2010
22
●
●
●
thread trying to get() when queue is empty
will wait in wait set of queue
thread which successfully add()s an object
to queue will wake him up (and vice versa)
What is wrong?
●
No synchronization
SPL/2010
23
What is wrong? Guard atomicity
●
two Consumer threads and one producer The
●
queue is empty at first
●
consumers execute take() - block (size=0)
●
producer calls add() once, notifyAll()
●
●
both consumers wake up. both execute
vec_.remove(0)
precondition does not hold for one of them
SPL/2010
24
What is wrong? Wait atomicity
●
one producer and one consumer
●
first runs the consumer, calls take()
●
●
consumer checks condition, and is stopped right
after (scheduler)
producer calls add() successfully – calls
notifyAll() - no thread in wait set at that time
●
consumer is resumed and calls this.wait()
●
queue not empty-consumer miss notification.
SPL/2010
25
Guard Atomicity - while loop
SPL/2010
26
Solution?
●
●
●
while loop ensures after waking up,
checks precondition one more time
no synchronization
use notify() instead of notifyAll() ?
dangerous...
SPL/2010
27
Wait Atomicity
●
●
ensure no one calls notify() between
precondition check and wait.
make both check and wait atomic with
relation to notify mechanism.
●
use single lock to protect them (?)
SPL/2010
28
Wait Atomicity
●
thread get hold of a lock
●
check
●
wait() - enter a wait set
●
no other thread may get lock and wake us up!
SPL/2010
29
Wait Atomicity
●
Java solution:
●
call to wait() or notifyAll() - calling thread must
hold object's monitor (lock).
●
enter wait() - thread (involuntarily) releases lock
●
before exit wait() - thread must relock object
(why?)
SPL/2010
30
SPL/2010
31
Wait/Notify Mechanism
●
thread T calls o.wait()
●
JVM checks that T holds o's lock
(if not, exception IllegalMonitorState).
●
T is blocked, and lock of o is released.
●
JVM places T in the wait set associated with o.
SPL/2010
32
Wait/Notify Mechanism
●
thread T calls o.notify()
●
●
●
●
JVM checks that T holds o's lock. if not
exception is thrown.
arbitrarily thread T' is removed from wait set
T' tries to re-acquire the lock of o (T' blocks
until it does).
T' is resumed from the point of its wait().
SPL/2010
33
Wait/Notify Mechanism
●
o.notifyAll() - steps occur simultaneously for
all threads in wait set of o.
●
●
Thundering Herd phenomena – all threads try to
acquire the lock competing with each other.
holding the monitor's lock check is done at
runtime and not at compile time.
SPL/2010
34
SPL/2010
35
SPL/2010
36
Rules of Thumb for Wait and Notify
●
Guarded wait - for each condition that needs
to be waited on, write a guarded wait loop
that causes the current thread to block if
the guard condition is false.
SPL/2010
37
Rules of Thumb for Wait and Notify
●
●
Guard atomicity - Condition checks must
always be placed in while loops.
When action is resumed, waiting thread
doesn't know if condition is true
●
●
to maintain safety, it must check again.
thread can wake up without notify, interrupt, or
timing out - spurious wakeup.
SPL/2010
38
Rules of Thumb for Wait and Notify
●
Multiple guard atomicity If there are
several conditions which need to be waited
for, place them all in the same loop.
SPL/2010
39
Rules of Thumb for Wait and Notify
●
Don't forget to wake up - ensure liveness,
classes must wake up waiting threads.
●
when value of field in guard changes - waiting
threads must be awakened to recheck conditions
SPL/2010
40
Rules of Thumb for Wait and Notify
●
notifyAll() - multiple threads wait on same
wait set:
●
●
at least two threads waiting for different
conditions,
ensure that no thread misses an event.
SPL/2010
41
notify() Vs. notifyAll():
●
●
●
queue which has add() / addTwo() methods
Thread t1 waits for queue in add() checking room
for one object,
thread t2 waits in addTwo() checking room for
two objects.
●
get() method calls notify() and thread t2 wakes up
●
room for one object in queue, t2 goes back to sleep.
●
t1 will not be woken up at all, even though there is
space in the queue.
SPL/2010
42
Sophisticated Primitives
●
●
Wait and Notify:
●
basis for higher level constructs.
●
general constructs
Specific mechanisms make code easier to
understand and demand less details when
using them:
●
Semaphores
●
Readers-Writers locks.
SPL/2010
43
Semaphores
●
Object controls bounded number of permits
(permit = train ticket):
●
●
●
Threads ask semaphore for permit (a ticket).
If semaphore has permits available, one permit is
assigned to requesting thread.
If no permit available, requesting thread is
blocked until permit is available
–
SPL/2010
when a thread returns permit received earlier
44
implementation
SPL/2010
45
Java Semaphore class properties
●
●
●
●
not re-entrant – thread calls acquire() twice,
must release() twice!
semaphore can be released by a thread other
than owner (unlike lock) – no ownership.
constructor accepts fairness parameter – if
t1 requested before t2 it will receive first
services as tryAcquire and managing permits.
SPL/2010
46
SimpleQueue vs. Semaphore
●
●
●
●
SQ: add(),remove() call notifyAll() call.
Sem: release() calls notifyAll() method
acquire() does not.
SQ:add(), remove() call wait()
Sem: method acquire() calls wait() method
release() does not.
●
SPL/2010
47
SimpleQueue vs. Semaphore
●
●
SQ: add(),remove() - non-empty
preconditions correspond to 2 distinct states
of the Queue: empty or full.
Sem: acquire() has pre-condition and
release() has no pre-condition.
●
●
release() does not need to call wait().
acquire() call wait() - symmetric call in release()
for notifyAll() (for each wait() - corresponding
notifyAll() that unblocks).
SPL/2010
48
Readers/Writers Example
●
●
allow readers and writers to access a shared
resource under different policies
Policy:
●
several readers can access resource together
●
only one writer can access resource at given time
●
Example:
–
–
SPL/2010
Readers wait if writer is pending
One writer at a time can access the shared resource,
if no readers are reading from it
49
SPL/2010
50
SPL/2010
51