Chapter 4 Shared Objects &

Shared Objects & Concepts: process interference. Mutual Exclusion mutual exclusion and locks. Models: model checking for interference modelling mutual exclusion

Practice: interference in shared Java objects mutual exclusion in Java (synchronized objects/methods).

1 2 2015 Concurrency: shared objects & mutual exclusion ©Magee/Kramer 2nd Edition 2015 Concurrency: shared objects & mutual exclusion ©Magee/Kramer 2nd Edition

A Concert Hall Booking System Concert Hall Booking System

const False = 0 A central computer connected to remote terminals via communication links const True = 1 is used to automate seat reservations for a concert hall. range Bool = False..True

To book a seat, a client chooses a free seat and the clerk enters the number SEAT = SEAT[False], of the chosen seat at the terminal and issues a ticket, if it is free. SEAT[reserved:Bool] = ( when (!reserved) reserve -> SEAT[True] A system is required which avoids double bookings of the same seat whilst | query[reserved] -> SEAT[reserved] allowing clients free choice of the available seats. | when (reserved) reserve -> ERROR //error of reserved twice Construct an abstract model of the system and demonstrate that your model does ). not permit double bookings. Like STOP, ERROR range Seats = 1..2 is a predefined FSP ||SEATS = (seat[Seats]:SEAT). local process (state), numbered -1 in the 3 equivalent LTS. 4 2015 Concurrency: shared objects & mutual exclusion ©Magee/Kramer 2nd Edition 2015 Concurrency: shared objects & mutual exclusion ©Magee/Kramer 2nd Edition Concert Hall Booking System Concert Hall Booking System – no interference?

LOCK = (acquire -> release -> ). TERMINAL = (choose[s:Seats] //lock for the booking system -> seat[s].query[reserved:Bool] -> if (!reserved) then TERMINAL = (choose[s:Seats] -> acquire (seat[s].reserve -> TERMINAL) -> seat[s].query[reserved:Bool] else -> if (!reserved) then TERMINAL (seat[s].reserve -> release-> TERMINAL) ). else (release -> TERMINAL) set Terminals = {a,b} ).

||CONCERT = ( Terminals:TERMINAL || Terminals::SEATS ). set Terminals = {a,b}

||CONCERT = (Terminals:TERMINAL || Terminals::SEATS Does this system allow double booking of a seat? || Terminals::LOCK).

5 Would locking at the seat level permit more concurrency? 6 2015 Concurrency: shared objects & mutual exclusion ©Magee/Kramer 2nd Edition 2015 Concurrency: shared objects & mutual exclusion ©Magee/Kramer 2nd Edition

4.1 Interference ornamental garden Program - class diagram

Ornamental garden problem: Apple t Thread People enter an ornamental garden through either of two turnstiles. Management wish to know how many are in the garden east,west Turnstile people Counter at any time. Garden Garden init() run() increment() go()

eastD, display display West people East westD, NumberCanvas counterD Turnstile Turnstile setvalue()

The Turnstile thread simulates the periodic arrival of a visitor to The concurrent program consists of two concurrent threads and a the garden every second by sleeping for a second and then invoking shared counter object. the increment() method of the counter object. 7 8 2015 Concurrency: shared objects & mutual exclusion ©Magee/Kramer 2nd Edition 2015 Concurrency: shared objects & mutual exclusion ©Magee/Kramer 2nd Edition ornamental garden program Turnstile class

The Counter object and Turnstile threads are created by the class Turnstile extends Thread { NumberCanvas display; go() method of the Garden applet: Counter people; The run()

private void go() { Turnstile(NumberCanvas n,Counter c) method exits counter = new Counter(counterD); { display = n; people = c; } and the thread terminates after west = new Turnstile(westD,counter); public void run() { Garden.MAX east = new Turnstile(eastD,counter); try{ visitors have west.start(); display.setvalue(0); entered. east.start(); for (int i=1;i<=Garden.MAX;i++){ Thread.sleep(500); //0.5 second between arrivals

} display.setvalue(i); people.increment(); Note that counterD, westD and eastD are objects of } NumberCanvas used in chapter 2. } catch (InterruptedException e) {} } 9 } 10 2015 Concurrency: shared objects & mutual exclusion ©Magee/Kramer 2nd Edition 2015 Concurrency: shared objects & mutual exclusion ©Magee/Kramer 2nd Edition

Counter class ornamental garden program - display

class Counter { int value=0; NumberCanvas display;

Counter(NumberCanvas n) { Hardware interrupts can occur display=n; at arbitrary times. display.setvalue(value); } The counter simulates a hardware interrupt during an void increment() { increment(), between int temp = value; //read value reading and writing to the Simulate.HWinterrupt(); shared counter value. value=temp+1; //write value Interrupt randomly calls After the East and West turnstile threads have each incremented display.setvalue(value); Thread.sleep() to force its counter 20 times, the garden people counter is not the sum } a thread switch. of the counts displayed. Counter increments have been lost. } Why? 11 12 2015 Concurrency: shared objects & mutual exclusion ©Magee/Kramer 2nd Edition 2015 Concurrency: shared objects & mutual exclusion ©Magee/Kramer 2nd Edition concurrent method activation ornamental garden Model

go Java method activations are not atomic - thread objects east go end GARDEN and west may be executing the code for the increment method end arrive at the same time. value east: value:VAR TURNSTILE display read go west write shared code east end PC arrive value PC increment: west: program TURNSTILE counter program read value counter Process VAR models read and write access to the shared counter value. write value + 1 Increment is modeled inside TURNSTILE since Java method activations are not atomic i.e. thread objects east and west may interleave their read and write actions. 13 14 2015 Concurrency: shared objects & mutual exclusion ©Magee/Kramer 2nd Edition 2015 Concurrency: shared objects & mutual exclusion ©Magee/Kramer 2nd Edition

ornamental garden model checking for errors - animation

const N = 4 range T = 0..N The alphabet of shared Scenario checking - set VarAlpha = { value.{read[T],write[T]} } process VAR is declared use animation to

explicitly as a set produce a trace. VAR = VAR[0], constant, VarAlpha. VAR[u:T] = (read[u] ->VAR[u] |write[v:T]->VAR[v]). The TURNSTILE TURNSTILE = (go -> RUN), alphabet is extended Is this trace RUN = (arrive-> INCREMENT with VarAlpha to correct? |end -> TURNSTILE), ensure no unintended INCREMENT = (value.read[x:T] free (autonomous) -> value.write[x+1]->RUN )+VarAlpha. actions in VAR such as value.write[0]. ||GARDEN = (east:TURNSTILE || west:TURNSTILE || { east,west,display}::value:VAR) All actions in the /{ go /{ east,west} .go, shared must be end/{ east,west} .end} . VAR controlled (shared) by 15 16 2015 Concurrency: shared objects & mutual exclusion a TURNSTILE©Magee/Kramer 2nd Edition. 2015 Concurrency: shared objects & mutual exclusion ©Magee/Kramer 2nd Edition checking for errors - exhaustive analysis ornamental garden model - checking for errors

Exhaustive checking - compose the model with a TEST process which ||TESTGARDEN = (GARDEN || TEST). sums the arrivals and checks against the display value: Use LTSA to perform an exhaustive search for ERROR.

Trace to property violation in TEST: TEST = TEST[0], go TEST[v:T] = east.arrive (when (vTEST[v+1] east.value.read.0 |end->CHECK[v] west.arrive ), west.value.read.0 CHECK[v:T] = Like STOP, ERROR east.value.write.1 LTSA produces the (display.value.read[u:T] -> is a predefined FSP west.value.write.1 shortest path to (when (u==v) right -> TEST[v] local process (state), end reach ERROR. |when (u!=v) wrong -> ERROR numbered -1 in the display.value.read.1 ) equivalent LTS. wrong )+{display.VarAlpha}.

17 18 2015 Concurrency: shared objects & mutual exclusion ©Magee/Kramer 2nd Edition 2015 Concurrency: shared objects & mutual exclusion ©Magee/Kramer 2nd Edition

Interference and Mutual Exclusion (mutex) 4.2 Mutual exclusion in Java

Concurrent activations of a method in Java can be made Destructive update, caused by the arbitrary interleaving of mutually exclusive by prefixing the method with the keyword read and write actions, is termed interference. synchronized, which uses a lock on the object.

We correct COUNTER class by deriving a class from it and making the increment method synchronized: Interference bugs are extremely difficult to locate. The class SynchronizedCounter extends Counter { general solution is to give methods mutually exclusive access to shared objects. Mutual exclusion (often referred SynchronizedCounter(NumberCanvas n) acquire {super(n);} lock to as “mutex”)can be modeled as atomic actions. synchronized void increment() { super.increment(); release } lock } 19 20 2015 Concurrency: shared objects & mutual exclusion ©Magee/Kramer 2nd Edition 2015 Concurrency: shared objects & mutual exclusion ©Magee/Kramer 2nd Edition mutual exclusion - the ornamental garden Java synchronized statement Access to an object may also be made mutually exclusive by using the synchronized statement: synchronized (object) { statements }

A less elegant way to correct the example would be to modify the Turnstile.run() method:

synchronized(people) {people.increment();}

Why is this less elegant? Java associates a lock with every object. The Java inserts code to acquire the lock before executing the body of the synchronized method and code to release the lock before the To ensure mutually exclusive access to an object, method returns. Concurrent threads are blocked until the lock is all object methods should be synchronized. released. 21 22 2015 Concurrency: shared objects & mutual exclusion ©Magee/Kramer 2nd Edition 2015 Concurrency: shared objects & mutual exclusion ©Magee/Kramer 2nd Edition

4.3 Modeling mutual exclusion Revised ornamental garden model - checking for errors

go To add locking to our model, define a LOCK, compose it with the A sample animation shared VAR in the garden, and modify the alphabet set : east.arrive execution trace east.value.acquire LOCK = (acquire->release->LOCK). east.value.read.0 ||LOCKVAR = (LOCK || VAR). east.value.write.1 set VarAlpha = {value.{read[T],write[T], east.value.release acquire, release}} west.arrive west.value.acquire Modify TURNSTILE to acquire and release the lock: west.value.read.1 TURNSTILE = (go -> RUN), west.value.write.2 RUN = (arrive-> INCREMENT west.value.release |end -> TURNSTILE), end INCREMENT = (value.acquire display.value.read.2 -> value.read[x:T]->value.write[x+1] right -> value.release->RUN Use TEST and LTSA to perform an exhaustive check. )+VarAlpha. 23 Is TEST satisfied? 24 2015 Concurrency: shared objects & mutual exclusion ©Magee/Kramer 2nd Edition 2015 Concurrency: shared objects & mutual exclusion ©Magee/Kramer 2nd Edition COUNTER: Abstraction using action hiding COUNTER: Abstraction using action hiding

To model shared objects directly Minimized in terms of their synchronized increment increment increment increment const N = 4 LTS: methods, we can abstract the range T = 0..N 0 1 2 3 4 details by hiding. VAR = VAR[0], For SynchronizedCounter VAR[u:T] = ( read[u]->VAR[u] we hide read, write, We can give a more abstract, simpler description of a COUNTER | write[v:T]->VAR[v]). acquire, release actions. which generates the same LTS: LOCK = (acquire->release->LOCK). COUNTER = COUNTER[0] INCREMENT = (acquire->read[x:T] COUNTER[v:T] = (when (v COUNTER[v+1]). -> (when (xrelease->increment->INCREMENT ) This therefore exhibits equivalent behavior i.e. has the same )+{read[T],write[T]}. observable behavior. ||COUNTER = (INCREMENT||LOCK||VAR)@{increment}.

25 26 2015 Concurrency: shared objects & mutual exclusion ©Magee/Kramer 2nd Edition 2015 Concurrency: shared objects & mutual exclusion ©Magee/Kramer 2nd Edition

4.4 Java Concurrency Utilities Package Counter – with an explicit lock

Java SE 5 intriduced a package of advanced concurrency utilities in class LockedCounter extends Counter { java.util.concurrent, later extended in JSE8. final ReentrantLock inclock = new ReentrantLock();

This includes many additional, explicit mechanisms such as atomic LockedCounter(NumberCanvas n) variables, a task scheduling framework (for thread and thread pool {super(n);} instantiation and control), and synchronizers such as semaphores public void increment()throws InterruptedException { (later), mutexes, barriers and explicit locks with timeout. inclock.lock(); try { synchronized: implicit lock associated with each object, super.increment(); block structured and recursive (reentrant) } finally {inclock.unlock();} } (Java mutex and POSIX pthread mutexes are not reentrant) } Lock interface: explicit lock objects, with methods Explicit locks are more dangerous and less efficient than synchronized. Use only if lock(), unlock(), tryLock() with optional timeout. required for non-block structured situations requiring flexibility (such as chain ReentrantLock: implements Lock (optionally fair), reentrant with methods locking: acquire lock on A, then on B, then release A and acquire C, …) or for other (At the memory level, volatile lock(), unlock(), tryLock() with optional timeout, … 27 advanced features such as timed or polled lock acquisition. 28 2015 Concurrency: shared objects & mutual exclusion ©Magee/Kramer 2nd Edition can2015 be used Concurrency: to force sharedreads/writes objects &on mutual a shared exclusion variable to main memory rather than cached©Magee/Kramer thread-locally) 2nd Edition . Summary

! Concepts " process interference " mutual exclusion and locks ! Models " model checking for interference " modelling mutual exclusion ! Practice " thread interference in shared Java objects " mutual exclusion in Java (synchronized objects/methods).

29 2015 Concurrency: shared objects & mutual exclusion ©Magee/Kramer 2nd Edition