Title: Web Programming Course
1Web Programming Course
- Lecture 5 Concurrent Programming 2
2Why Synchronization?
- public class Stack
-
- int top0
- int data new int10
- public void push(int num)
-
- datatopnum
- top top 1
-
-
- public int pop()
-
- top top - 1
- return datatop
-
3Why Synchronization?
- push() consists of 2 operations
- store the element into datatop
- increment top
- If push() was started, it is supposed to be
completed with no interrupts. - Consider the following example of two threads
using push() method
4Why Synchronization?
- class PushThread extends Thread
- Stack stack
-
- PushThread(Stack stack, String name)
- super(name)
- this.stackstack
-
- public void run()
- int number
- while (true)
- number(int)(Math.random()100) 1
- while (stack.isFull())
- stack.push(number)
-
-
5Why Synchronization?
- class PopThread extends Thread
- Stack stack
-
- PopThread(Stack stack, String name)
- super(name)
- this.stackstack
-
- public void run()
- int result
- while (true)
- while (stack.isEmpty())
- result stack.pop()
-
-
6Why Synchronization?
- public class StackDemo
- public static void main(String args)
- Stack stack new Stack()
- Thread push1new PushThread(stack,"push1_Thread"
) - Thread push2new PushThread(stack,"push2_Thread"
) -
- push1.start()
- push2.start()
- pop1.start()
- pop2.start()
-
-
7Why Synchronization?
top
- Consider a scenario
- Initially, the stack is empty, i.e., top0
- push1 calls to stack.push(1)
- push2 calls to stack.push(2)
- push1 performs data01 //top0
- push2 performs data02 //top0
- push1 performs top //top1
- push2 performs top //top2
3
2
1
0
8Race Condition
- Race condition The situation where several
processes access and manipulate shared data (or
resource memory, file, stream) concurrently. - The final value of the shared data depends upon
which process finishes last. - To prevent race conditions, concurrent processes
must be synchronized.
9The Critical-Section Problem
- n running processes are competing to use the same
shared data. - Each process has a code segment, called critical
section, in which the shared data is accessed. - Problem ensure that when one process is
executing its critical section, no other process
is allowed to execute its critical section.
10Critical-Section Problem
- Mutual exclusion - If a process Pi is executing
its CS, no other processes can be executing their
CS. - Progress - If no process is executing its CS and
there exist some processes that wish to enter
their CS, then their enter will not be postponed
indefinitely. - Bounded Waiting - A bound must exist on the
number of times that other processes are allowed
to enter their CS after a process has made a
request to enter its CS and before that request
is granted.
11Critical Sections
12Critical Sections
- Execution of the critical section will require
atomicity - Execution by one thread only
- Either does not start or fully completes
- If the execution has started, it will be
completed - No interruptions
13Critical Sections
- Synchronization Methods
- Locks
- Semaphores
- Monitors
- Synchronization Problems
- Producer-Consumer Problem
- Bounded Buffer Problem
- Readers-Writers Problem
14Synchronization attempt 1
- Process A
Process B - ... ...
- while( TRUE ) while( TRUE )
- ... ...
- while( o.proc B ) while( o.proc
A ) - lt criticalA gt lt criticalB gt
- o.proc B o.proc A
- ... ...
-
- ... ...
- Problem violates rule 2 (strict alteration).
15Synchronization attempt 2
- Process A Process B
- ... ...
- while( TRUE ) while( TRUE )
- ... ...
- while( o.pBinside ) while( o.pAinside
) - o.pAinside TRUE o.pBinside TRUE
- lt criticalA gt lt criticalB gt
- o.pAinside FALSE o.pBinside
FALSE - ... ...
-
- ... ...
- Problem violates rule 1 (interleaved
instructions).
16Hardware Solution
- Synchronization solutions are based on hardware
level operations - Many CPUs support atomic read-modify-write
operations - TAS test-and-set (Motorola 68K)
- CAS compare-and-swap (IBM 370 and Motorola 68K)
- XCHG exchange (x86)
17Hardware Solution
- Example using test-and-set (TAS)
18Semaphores
- A semaphore is a synchronization variable that
takes on non-negative integers with two atomic
operations - P() while ( semaphore lt 0 )
- //wait()
- semaphore--
- V() semaphore
- //signal()
-
- Semaphores are simple, yet elegant, and allow the
solution of many problems. They are useful for
more than just mutual exclusion.
19Object-Oriented Semaphore
- class Semaphore
- private int value
-
- //initialized with non-negative value
- public Semaphore(int val) value val
-
- public void down()
- while (value lt 0 )
- value--
-
-
- public void up()
- value
-
20Properties of semaphores
- Semaphores are not provided by hardware, but they
have several attractive properties - Simple.
- Single resource works with many threads.
- Can have many different critical sections with
different semaphores. - Each critical section has unique access
semaphore. - Can permit multiple threads into the critical
section at once.
21Possible Use of Semaphores
- Mutual exclusion initialize the semaphore to one
simultaneous thread in CS. - init Semaphore mutexnew Semaphore(1)
- 1 mutex.down()
- 2 func()
- 3 mutex.up()
22Type of semaphores
- Semaphores are usually available in two flavors
- Binary is a semaphore with an integer value of
0 and 1. - Counting is a semaphore with an integer value
ranging between 0 and an arbitrarily large
number. - Its initial value represents the number of units
of the critical resources that are available. - This form is also known as a general semaphore.
- Semaphore are considered parts of the basic
synchronization services.
23Implementation of semaphores
- No existing hardware implements Up() and Down()
operations directly. - Semaphores are built-up in software using
elementary hardware synchronization primitives. - Naïve uni-processor solution disable interrupts.
24Monitors
- Although semaphores solve synchronization
problems, they provide low-level and error-prone
solutions. - A better (higher-level) solution is provided by
the monitor - A mutex semaphore is associated with a shared
resource and any piece of code that touches these
variables is preceded by mutex.down() and
followed by mutex.up(). - Why not to let the compiler to do this work?
25Monitors in Java
- Using the synchronized keyword
- Synchronization order
- Gain a monitor (lock)
- Perform the desired operation
- Release the monitor
- Thread can not access the CS without obtaining
the lock
26Synchronized Methods
- A synchronized method locks the current object
such that no other thread can execute inside the
object while the method is active. - By locking the object, we guarantee that its
state will remain consistent during the duration
in which the lock on the object is held by a
thread. - When the lock is released, then another thread
can lock the object and update its state.
27Synchronized Objects
- Java objects are all lockable objects.
- Every object in Java is a subtype of the Object
class in Java. - The Object class implements an implicit locking
mechanism that allows any object to be locked
during a synchronized method or synchronized
block - This provides mutual exclusion
28Object-Level Synchronization
- public void push(int num)
- synchronized(this)
- datatopnum
- top
-
-
- public int pop()
- synchronized(this)
- top--
- return datatop
-
-
29Method-Level Synchronization
- public synchronized void push(int num)
- datatopnum
- top
-
- public synchronized int pop()
- top--
- return datatop
-
30Java Synchronization Example
t1
t2
t3
synchronized(this) ...
Note, that mutual exclusion holds between
synchronized pieces of code only!!
Object-level synchronization
31Method-level or Object-level
- Synchronization decreases parallelization
- It is preferable to synchronize the critical
sections only - Object-level synchronization
- However, object-level synchronization is
impossible for static methods - Synchronized static methods of a class can not be
executed in parallel
32Synchronization Example
class InternetBankingSystem public
static void main(String args )
Account accountObject new Account ()
Thread t1 new Thread(new MyThread(accountObje
ct)) Thread t2 new Thread(new
YourThread(accountObject)) Thread t3 new
Thread(new HerThread(accountObject))
t1.start() t2.start()
t3.start() // do some other operation
// end main()
33Synchronization Example
class MyThread implements Runnable Account
account public MyThread (Account s)
account s public void run()
account.deposit() // end class
MyThread class YourThread implements Runnable
Account account public YourThread
(Account s) account s public void
run() account.withdraw() // end class
YourThread class HerThread implements Runnable
Account account public HerThread
(Account s) account s public void
run() account.enquire() // end class
HerThread
account (shared object)
34Synchronization Example
- class Account // the 'monitor'
- int balance
- // if 'synchronized' is removed, the outcome is
unpredictable - public synchronized void deposit( )
- // METHOD BODY balance deposit_amount
-
- public synchronized void withdraw( )
- // METHOD BODY balance - deposit_amount
-
- public synchronized void enquire( )
- // METHOD BODY display balance.
-
35Synchronization Example
- 3 methods f1(), f2() and f3() in MyClass
- Neither 2 instances of f1() nor 2 instances of
f2() can be executed in parallel - However, defining them as synchronized will not
allow to execute f1() in parallel with f2()
36Synchronization Example
- Solution defining 2 different monitors
- private static Object sync_f1 new Object()
- private static Object sync_f2 new Object()
- And synchronizing on these monitors
- void f1()
- synchronized (sync_f1)
- ... // code of f1()
-
-
- void f2()
- synchronized (sync_f2)
- ... // code of f2()
-
37Synchronization Example
- f3() can not be executed in parallel neither with
f1() nor with f2() - Solution
- void f3()
- synchronized (sync_f1)
- synchronized (sync_f2)
- ...// code of f3()
-
-
38Wait(), Notify(), and NotifyAll()
- Synchronized methods are methods that lock the
object on entry and unlock the object on exit. - The Object class implements some special methods
for allowing a thread to - explicitly release the lock while in the method
- wait for the lock for some time
- notify other threads
39Wait(), Notify(), and NotifyAll()
- wait() causes a thread to wait (indefinitely or
for some time interval), and then try to
reacquire the lock - notify() signals one (defined at the run-time)
thread to wakeup - notifyAll() signals all threads to wakeup and
compete to re-acquire the lock - If no thread is waiting, then notify() and
notifyAll() have no effect
40Wait(), Notify(), and NotifyAll()
- These methods should be used only from within
methods holding the object lock - If called without holding the lock, the
IllegalMonitorStateException is thrown - A waiting (or sleeping) thread can also be awoken
if it is interrupted by another thread - In this case, the InterruptedException is thrown
41Producer-Consumer Problem
- Correct behavior is
- Producer puts 1 value in buffer
- Then Consumer reads it
- And so on
- If no concurrency control on Buffer
- If Producer is quicker than Consumer, Consumer
will skip 1 or more values - Vice versa, Consumer will read same values 2 or
more times - Need to synchronize the work of Producer and
Consumer
42Producer-Consumer Example
- class Producer extends Thread
- private Buffer buf
- private int number // id
- public Producer(Buffer b, int n)
- buf b number n
- public void run()
- for (int i 0 i lt 10 i)
- buf.put(i)
- System.out.println(
- "Producer " number
- " put " i)
- //random sleep ...
-
-
- class Consumer extends Thread
- private Buffer buf
- private int number // id
- public Consumer(Buffer b, int n)
- buf b number n
- public void run()
- int value 0
- for (int i 0 i lt 10 i)
- value buf.get()
- System.out.println(
- "Consumer " number
- " got " value)
-
-
43Expected Output
- Producer 1 put 0
- Consumer 1 got 0
- Producer 1 put 1
- Consumer 1 got 1
- Producer 1 put 2
- Consumer 1 got 2
- Producer 1 put 3
- Consumer 1 got 3
- Producer 1 put 4
- Consumer 1 got 4
-
- Producer 1 put 5
- Consumer 1 got 5
- Producer 1 put 6
- Consumer 1 got 6
- Producer 1 put 7
- Consumer 1 got 7
- Producer 1 put 8
- Consumer 1 got 8
- Producer 1 put 9
- Consumer 1 got 9
44Synchronized Produce-Consumer
- class Buffer
- //shared resource
- private int num -1 //invalid
-
- public synchronized int get()
- return num
-
- public synchronized void put(int value)
- num value
-
45Synchronized Produce-Consumer
- public class ProducerConsumerTest
- public static void main()
- Buffer b new Buffer()
- Producer p1new Producer(b, 1)
- Consumer c1new Consumer(b, 1)
- p1.start()
- c1.start()
-
46Does it work?
- Synchronized ensures only that
- put() and get() cannot be invoked at exactly the
same time (no overwriting while reading) - In case there are multiple producers and/or
consumers, they queue up nicely - It does not ensure alternation
- e.g. Consider a case in which Consumer calls
get() before Producer had a chance to call put() - One or more times
- We need some device for threads explicitly
coordinating with each other!
47Synchronized Produce-Consumer
- public synchronized void consume()
- while (!consumable())
- wait() // release lock and wait for resource
-
- ... //have exclusive access to resource to
consume -
- public synchronized void produce()
- ... //change of state must result in consumable
condition being true - notifyAll() // notify all waiting threads to
try consuming
48Synchronized Produce-Consumer
- class Buffer
- private int num
- private boolean availablefalse
- public synchronized int get()
- while (available false)
- try this.wait()
- catch(InterruptedException e)e.printStackTrac
e() -
- available false
- this.notifyAll()
- return num
-
- public synchronized void put(int value)
- while (available true)
- try this.wait()
- catch(InterruptedException e)e.printStackTrac
e() -
- num value
- available true
49Condition Variables
- When a thread is awoken, it cannot assume that
its condition is true, as all threads are
potentially awoken by notifyAll() - One would expect that the thread can assume that
when it awakes, the shared resource is in the
appropriate state - This is not always the case
50Condition Variables
- Another thread could get access to the shared
resource and modify it - When the thread eventually gains access to the
lock, the shared resource can again be
inaccessible - Hence, it is usually essential for threads to
re-evaluate their guards
51Bounded Buffer Example
public class BoundedBuffer private int
buffer private int first private int
last private int numberInBuffer 0 private
int size public BoundedBuffer(int length)
size length buffer new intsize
last 0 first 0
52Bounded Buffer Example
public synchronized void put(int item)
throws InterruptedException while
(numberInBuffer size) wait() last
(last 1) size // modulus
numberInBuffer bufferlast item
notifyAll() public synchronized int
get() throws InterruptedException
while (numberInBuffer 0) wait() first
(first 1) size // modulus
numberInBuffer-- notifyAll() return
bufferfirst
53Readers-Writers Problem
- Many reader and writer threads are attempting to
access an object storing a large data structure - Readers can read concurrently, as they do not
alter the data - Writers require mutual exclusion over the data
both from other writers and from readers - Priority is always given to waiting writers
- As soon as a writer is available, all new readers
will be blocked until all writers have finished
54Readers-Writers Problem
- Standard solution requires 4 monitor methods,
which are used
startRead() // call object to read data
structure stopRead()
startWrite() // call object to write data
structure stopWrite()
55Readers-Writers Problem
- Standard solution in monitors is to have two
condition variables OkToRead and OkToWrite - This cannot be directly expressed using a single
Java monitor
public class ReadersWriters private int
readers 0 private int waitingWriters 0
private boolean writing false
56Readers-Writers Problem
public synchronized void StartWrite()
while(readers gt 0 writing)
waitingWriters wait()
waitingWriters-- writing true
public synchronized void StopWrite()
writing false notifyAll()
loop to re-test the condition
Wakeup everyone
57Readers-Writers Problem
public synchronized void StartRead()
throws InterruptedException while(writing
waitingWriters gt 0) wait() readers
public synchronized void StopRead()
readers-- if(readers 0) notifyAll()
58Starvation and Deadlock
- Starvation situation where a thread is
continuously deferred by the scheduler - Deadlock situation two or more threads can not
proceed, since they are waiting for each other
59Deadlock Necessary Conditions
- Mutual Exclusion
- Each processor has exclusive use of its resources
- Non-preemption
- A process never releases resources until it has
finished using them - Resource waiting
- Each process holds resources while waiting for
other processes to release theirs - Cycle of waiting processes
- Each process in the cycle waits for resources
that the next process owns and will not relinquish
60(No Transcript)
61Dining Philosophers Problem
- A philosopher can
- Think
- Gives up the two chopsticks on right and left
- Eat
- Picks up the two chopsticks on right and left one
at a time - If chopstick is in use, must wait until neighbor
thinks and then picks it up
62Dining Philosophers Problem
- Deadlock Scenario
- Philosopher 1 takes his right chopstick
- Philosopher 2 takes his right chopstick
- Philosopher 3 takes his right chopstick
-
- What are the deadlock conditions in this scenario?