Programming Language Concepts: Lecture 11 Madhavan Mukund Chennai - - PowerPoint PPT Presentation

programming language concepts lecture 11
SMART_READER_LITE
LIVE PREVIEW

Programming Language Concepts: Lecture 11 Madhavan Mukund Chennai - - PowerPoint PPT Presentation

Programming Language Concepts: Lecture 11 Madhavan Mukund Chennai Mathematical Institute madhavan@cmi.ac.in PLC 2011, Lecture 11, 01 March 2011 Concurrent Programming Monitors [Per Brinch Hansen, CAR Hoare] Attach synchronization control


slide-1
SLIDE 1

Programming Language Concepts: Lecture 11

Madhavan Mukund

Chennai Mathematical Institute madhavan@cmi.ac.in

PLC 2011, Lecture 11, 01 March 2011

slide-2
SLIDE 2

Concurrent Programming

Monitors [Per Brinch Hansen, CAR Hoare]

◮ Attach synchronization control to the data that is being

protected

◮ Monitor is like a class in an OO language

◮ Data definition — to which access is restricted across threads ◮ Collections of functions operating on this data — all are

implicitly mutually exclusive

◮ Monitor guarantees mutual exclusion — if one function is

active, any other function will have to wait for it to finish

slide-3
SLIDE 3

Monitors

monitor bank_account{ double accounts[100]; boolean transfer (double amount, int source, int target){ // transfer amount accounts[source] -> accounts[target] if (accounts[source] < amount){ return false; } accounts[source] -= amount; accounts[target] += amount; return true; } double audit(){ // compute the total balance across all accounts double balance = 0.00; for (int i = 0; i < 100; i++){ balance += accounts[i]; } return balance; } }

slide-4
SLIDE 4

Monitors . . .

transfer(500.00,i,j); transfer(400.00,j,k);

◮ Mechanism for a thread to suspend itself and give up the

monitor

◮ A suspended process is waiting for monitor to change its state ◮ Separate internal queue, as opposed to external queue where

initially blocked threads wait

◮ Dual operation to wake up suspended processes

slide-5
SLIDE 5

Monitors . . .

boolean transfer (double amount, int source, int target){ while (accounts[source] < amount){ wait(); } accounts[source] -= amount; accounts[target] += amount; notify(); return true; }

What happens when a process executes notify()?

◮ Signal and exit — notifying process immediately exits the

monitor

◮ Signal and wait — notifying process swaps roles and goes into

the internal queue of the monitor

◮ Signal and continue — notifying process keeps control till it

completes and then one of the notified processes steps in

slide-6
SLIDE 6

Monitors . . .

◮ Makes sense to have more than one internal queue

monitor bank_account{ double accounts[100]; queue q[100]; // one internal queue for each account boolean transfer (double amount, int source, int target){ while (accounts[source] < amount){ q[source].wait(); // wait in the queue associated with source } accounts[source] -= amount; accounts[target] += amount; q[target].notify(); // notify the queue associated with target return true; } }

slide-7
SLIDE 7

Monitors in Java

◮ Java implements monitors with a single internal queue ◮ Monitors incorporated within existing class definitions

slide-8
SLIDE 8

Monitors in Java

◮ Java implements monitors with a single internal queue ◮ Monitors incorporated within existing class definitions ◮ Function declared synchronized is to be executed atomically

◮ Trying to execute a synchronized function while another is in

progress blocks the second thread into an external queue

slide-9
SLIDE 9

Monitors in Java

◮ Java implements monitors with a single internal queue ◮ Monitors incorporated within existing class definitions ◮ Function declared synchronized is to be executed atomically

◮ Trying to execute a synchronized function while another is in

progress blocks the second thread into an external queue

◮ Each object has a lock

◮ To execute a synchronized method, thread must acquire lock ◮ Thread gives up lock when the method exits ◮ Only one thread can have the lock at any time

slide-10
SLIDE 10

Monitors in Java

◮ Java implements monitors with a single internal queue ◮ Monitors incorporated within existing class definitions ◮ Function declared synchronized is to be executed atomically

◮ Trying to execute a synchronized function while another is in

progress blocks the second thread into an external queue

◮ Each object has a lock

◮ To execute a synchronized method, thread must acquire lock ◮ Thread gives up lock when the method exits ◮ Only one thread can have the lock at any time

◮ wait() and notify() to suspend and resume

◮ notify() signals one (arbitrary) waiting process ◮ notifyAll() signals all waiting processes ◮ Java uses signal and continue

slide-11
SLIDE 11

Monitors in Java . . .

public class bank_account{ double accounts[100]; public synchronized boolean transfer (double amount, int source, int target){ while (accounts[source] < amount){ wait(); } accounts[source] -= amount; accounts[target] += amount; notifyAll(); return true; } public synchronized double audit(){ double balance = 0.0; for (int i = 0; i < 100; i++){ balance += accounts[i]; } return balance; } public double current_balance(int i){ // not synchronized! return accounts[i]; } }

slide-12
SLIDE 12

Object locks

◮ Every object has a lock in Java ◮ Can synchronize arbitrary blocks of code

public class XYZ{ Object o = new Object(); public int f(){ .. synchronized(o){ ... } } public double g(){ .. synchronized(o){ ... } } } }

slide-13
SLIDE 13

Object locks

◮ Every object has a lock in Java ◮ Can synchronize arbitrary blocks of code

public class XYZ{ Object o = new Object(); public int f(){ .. synchronized(o){ ... } } public double g(){ .. synchronized(o){ ... } } } }

◮ f() and g() can start in parallel ◮ Only one of the threads can grab the lock for o

slide-14
SLIDE 14

Object locks . . .

◮ Each object has its own internal queue

Object o = new Object(); public int f(){ .. synchronized(o){ ...

  • .wait();

// Wait in queue attached to "o" ... } } public double g(){ .. synchronized(o){ ...

  • .notifyAll();

// Wake up queue attached to "o" ... } }

slide-15
SLIDE 15

Object locks . . .

◮ Can convert methods from “externally” synchronized to

“internally” synchronized

public double h(){ synchronized(this){ ... } }

◮ “Anonymous” wait(), notify(), notifyAll() abbreviate

this.wait(), this.notify(), this.notifyAll()

slide-16
SLIDE 16

Object locks . . .

◮ Actually, wait() can be “interrupted” by an

InterruptedException

◮ Should write

try{ wait(); } catch (InterruptedException e) { ... };

slide-17
SLIDE 17

Object locks . . .

◮ Actually, wait() can be “interrupted” by an

InterruptedException

◮ Should write

try{ wait(); } catch (InterruptedException e) { ... };

◮ Error to use wait(), notify(), notifyAll() outside

synchronized method

◮ IllegalMonitorStateException

◮ Likewise, use o.wait(), o.notify(), o.notifyAll() only

in block synchronized on o

slide-18
SLIDE 18

Java threads

◮ Have a class extend Thread ◮ Define a function run() where execution can begin in parallel

public class Parallel extends Thread{ private int id; public Parallel(int i){ id = i; } public void run(){ for (int j = 0; j < 100; j++){ System.out.println("My id is "+id); try{ sleep(1000); // Go to sleep for 1000 ms } catch(InterruptedException e){} } } }

slide-19
SLIDE 19

Java threads . . .

Invoking threads

public class TestParallel { public static void main(String[] args){ Parallel p[] = new Parallel[5]; for (int i = 0; i < 5; i++){ p[i] = new Parallel(i); p[i].start(); // Start off p[i].run() // in concurrent thread } }

slide-20
SLIDE 20

Java threads . . .

Invoking threads

public class TestParallel { public static void main(String[] args){ Parallel p[] = new Parallel[5]; for (int i = 0; i < 5; i++){ p[i] = new Parallel(i); p[i].start(); // Start off p[i].run() // in concurrent thread } }

◮ p[i].start() initiates p[i].run() in a separate thread

◮ Directly calling p[i].run() does not execute in separate

thread!

slide-21
SLIDE 21

Java threads . . .

◮ sleep(...) is a static function in Thread

◮ Argument is time to sleep, in milliseconds ◮ Use Thread.sleep(...) if current class does not extend

Thread

◮ sleep(..) throws InterruptedException (like wait())

slide-22
SLIDE 22

Java threads . . .

◮ Cannot always extend Thread

◮ Single inheritance

◮ Instead, implement Runnable

public class Parallel implements Runnable{ // only this line // has changed private int id; public Parallel(int i){ ... } // Constructor public void run(){ ... } }

slide-23
SLIDE 23

Java threads . . .

◮ To use Runnable class, must explicitly create a Thread and

start() it

public class TestParallel { public static void main(String[] args){ Parallel p[] = new Parallel[5]; Thread t[] = new Thread[5]; for (int i = 0; i < 5; i++){ p[i] = new Parallel(i); t[i] = new Thread(p[i]); // Make a thread t[i] from p[i] t[i].start(); // Start off p[i].run() concurrently // Note: t[i].start(), not p[i].start() } } }

slide-24
SLIDE 24

Life cycle of a Java thread

A thread can be in four states

◮ New: Created but not start()ed. ◮ Runnable: start()ed and ready to be scheduled.

◮ Need not be actually “running” ◮ No guarantee made about how scheduling is done ◮ Most Java implementations use time-slicing

◮ Blocked: not available to run

◮ Within sleep(..) — unblocked when sleep timer expires ◮ Suspended by wait() — unblocked by notify() or

notfifyAll().

◮ Blocked on input/output — unblocked when the i/o succeeds.

◮ Dead: thread terminates.

slide-25
SLIDE 25

Interrupts

◮ One thread can interrupt another using interrupt()

◮ p[i].interrupt(); interrupts thread p[i]

◮ Raises InterruptedException within wait(), sleep()

slide-26
SLIDE 26

Interrupts

◮ One thread can interrupt another using interrupt()

◮ p[i].interrupt(); interrupts thread p[i]

◮ Raises InterruptedException within wait(), sleep() ◮ No exception raised if thread is running!

slide-27
SLIDE 27

Interrupts

◮ One thread can interrupt another using interrupt()

◮ p[i].interrupt(); interrupts thread p[i]

◮ Raises InterruptedException within wait(), sleep() ◮ No exception raised if thread is running!

◮ interrupt() sets a status flag ◮ interrupted() checks interrupt status and clears the flag

◮ Detecting an interrupt while running or waiting

public void run(){ try{ j = 0; while(!interrupted() && j < 100){ System.out.println("My id is "+id); sleep(1000); // Go to sleep for 1000 ms j++; } } catch(InterruptedException e){} }

slide-28
SLIDE 28

Interrupts

◮ Check another thread’s interrupt status using interrupted

◮ t.isInterrupted() to check status of t’s interrupt flag ◮ Does not clear flag

◮ isAlive() checks running status of a thread

◮ t.isAlive() is true if t is Runnable or Blocked ◮ t.isAlive() is false if t is New or Dead

◮ Can also stop(), suspend() and resume() a thread, but

should not!

slide-29
SLIDE 29

An exercise in concurrent programming

◮ A narrow North-South bridge can accommodate traffic only in

  • ne direction at a time.

◮ When a car arrives at the bridge

  • 1. Cars on the bridge going in the same direction ⇒ can cross
  • 2. No other car on the bridge ⇒ can cross (implicitly sets

direction)

  • 3. Cars on the bridge going in the opposite direction ⇒ wait for

the bridge to be empty

◮ Cars waiting to cross from one side may enter bridge in any

  • rder after direction switches in their favour.

◮ When bridge becomes empty and cars are waiting, yet another

car can enter in the opposite direction and makes them all wait some more.

slide-30
SLIDE 30

An example . . .

◮ Design a class Bridge to implement consistent one-way

access for cars on the highway synchronization primitives

◮ Should permit multiple cars to be on the bridge at one time

(all going in the same direction!)

◮ Bridge has a public method

public void cross(int id, boolean d, int s)

◮ id is identity of car ◮ d indicates direction ◮ true is North ◮ false is South ◮ s indicates time taken to cross (milliseconds)

slide-31
SLIDE 31

An example . . .

public void cross(int id, boolean d, int s)

◮ Method cross prints out diagnostics

  • 1. A car is stuck waiting for the direction to change

Car 7 going North stuck at Thu Mar 13 23:00:11 IST 2009

  • 2. The direction changes

Car 5 switches bridge direction to North at Thu Mar 13 23:00:14 IST 2009

  • 3. A car enters the bridge.

Car 8 going North enters bridge at Thu Mar 13 23:00:14 IST 2009

  • 4. A car leaves the bridge.

Car 16 leaves at Thu Mar 13 23:00:15 IST 2009

◮ Use java.util.Date to generate time stamps

slide-32
SLIDE 32

Analysis

◮ The “data” that is shared is the Bridge ◮ State of the bridge is represented by two quantities

◮ Number of cars on bridge — an int ◮ Current direction of bridge — a boolean

◮ The method

public void cross(int id, boolean d, int s)

changes the state of the bridge

◮ Concurrent execution of cross can cause problems . . . ◮ . . . but making cross a synchronized method is too restrictive ◮ Only one car on the bridge at a time ◮ Problem description explicitly disallows such a solution

slide-33
SLIDE 33

Analysis . . .

◮ Break up cross into a sequence of actions

◮ enter — get on the bridge ◮ travel — drive across the bridge ◮ leave — get off the bridge ◮ enter and leave can print out the diagnostics required

◮ Which of these affect the state of the bridge?

◮ enter : increment number of cars, perhaps change direction ◮ leave : decrement number of cars

◮ Make enter and leave synchronized ◮ travel is just a means to let time elapse — use sleep

slide-34
SLIDE 34

Analysis . . .

Code for cross

public void cross(int id, boolean d, int s){ // Get onto the bridge (if you can!) enter(id,d); // Takes time to cross the bridge try{ Thread.sleep(s); } catch(InterruptedException e){} // Get off the bridge leave(id); }

slide-35
SLIDE 35

Analysis . . .

Entering the bridge

◮ If the direction of this car matches the direction of the bridge,

it can enter

◮ If the direction does not match but the number of cars is zero,

it can reset the direction and enter

◮ Otherwise, wait() for the state of the bridge to change ◮ In each case, print a diagnostic message

slide-36
SLIDE 36

Code for enter

private synchronized void enter(int id, boolean d){ Date date; // While there are cars going in the wrong direction while (d != direction && bcount > 0){ date = new Date(); System.out.println("Car "+id+" going "+ direction_name(d)+" stuck at "+date); // Wait for our turn try{ wait(); } catch (InterruptedException e){} } ... }

slide-37
SLIDE 37

Code for enter

private synchronized void enter(int id, boolean d){ ... while (d != direction && bcount > 0){ ... wait() ...} ... // Switch direction, if needed if (d != direction){ direction = d; date = new Date(); System.out.println("Car "+id+" switches bridge direction to "+direction_name(direction)+" at "+date); } // Register our presence on the bridge bcount++; date = new Date(); System.out.println("Car "+id+" going "+direction_name(d)+" enters bridge at "+date); }

slide-38
SLIDE 38

Analysis . . .

Leaving the bridge is much simpler

◮ Decrement the car count ◮ notify() waiting cars

. . . provided car count is zero

private synchronized void leave(int id){ Date date = new Date(); System.out.println("Car "+id+" leaves at "+date); // "Check out" bcount--; // If everyone on the bridge has checked out, notify the // cars waiting on the opposite side if (bcount == 0){ notifyAll(); } }