170 likes | 278 Views
INFT13-310/73-310 Section 8 Concurrency II: Mutual Exclusion. http://www-dse.doc.ic.ac.uk/concurrency/. Using material from Magee and Kramer:. Issues How to model execution speed? arbitrary abstract away time How to model concurrent execution? actions in each process ordered
E N D
INFT13-310/73-310Section 8Concurrency II:Mutual Exclusion http://www-dse.doc.ic.ac.uk/concurrency/ Using material from Magee and Kramer:
Issues How to model execution speed? arbitrary abstract away time How to model concurrent execution? actions in each process ordered arbitrary relative ordering between processes (interleaving) Result: general (asynchronous) model independent of scheduling Parallel Composition If P and Q are processes, (P||Q) represents the concurrent execution of P and Q Modelling Concurrency E.g., PONDER = (think -> STOP). DINNER = (talk -> eat -> STOP). ||PONDINNER = (PONDER || DINNER). Traces: think -> talk -> eat. talk -> think -> eat. talk -> eat -> think. Laws of composition: (P || Q) = (Q || P) (P || (Q || R)) = ((P || Q) || R) = (P || Q || R)
Shared actions Processes in an interaction with actions in common share the actions: unshared actions can be arbitrarily interleaved shared actions are executed at the same time by all sharing processes E.g., MAKER = (make -> ready -> MAKER). USER = (ready -> use -> USER). ||MAKER_USER = (MAKER || USER). Handshake An action acknowledged by another E.g., MAKER2 = (make->ready->used->MAKER2). USER2 = (ready->use->used->USER2). ||MAKER_USER2 = (MAKER2 || USER2). Modelling Interaction How many states? How many traces?
Handshake: An action acknowledged by another E.g., MAKER_A = (makeA->ready->used->MAKER_A). MAKER_B = (makeB->ready->used->MAKER_B). ASSEMBLE = (ready->assemble->used->ASSEMBLE). ||FACTORY = (MAKER_A || MAKER_B || ASSEMBLE). Modelling Multi-party Synchronisation How many states? How many traces? makeA makeB makeA ready assemble 0 1 2 3 4 5 makeB used
HOMME = (B->o->n->j->o->u->r->HOMME). DEUTSCHER = (G->u->t->e->n->T->a->g->DEUTSCHER). MESS = (HOMME || DEUTSCHER). Guten Jour! public static void displayMessage( RepeatedMessage rm ) throws InterruptedException { for (int i = 0; i < rm.message.length(); i++) { System.out.print(rm.message.charAt(i)); sleep(50); } System.out.println(); } Sample output: BGount ejno uTra!g !B on jour! BoGnu tjeonu rT!a Bgo!n jour! BonG ujtoeunr !T Baogn! jour! BGount ejno uTra!g B!o n jouGru!t en Tag!
HOMME = (f_go->B->o->n->j->o->u->r->f_end->HOMME). DEUTSCHER = (g_go->G->u->t->e->n->T->a->g->g_end ->DEUTSCHER). SYSTEM = (f_go ->f_end ->SYSTEM | g_go ->g_end ->SYSTEM). NO_MESS = (HOMME || DEUTSCHER || SYSTEM). Bon Tag! public synchronized static void displayMessage( RepeatedMessage rm ) throws InterruptedException { for (int i = 0; i < rm.message.length(); i++) { System.out.print(rm.message.charAt(i)); sleep(50); } System.out.println(); } Sample output: Bon jour! Guten Tag! Bon jour! Guten Tag! Bon jour! Bon jour! Guten Tag!…
Interference: destructive update caused by arbitrary interleaving of read and write actions ETURN = (e:in->e:readCnt[ec]->e:writeCnt[ec+1]->ETURN | e:out->e:readCnt[ec]->e:writeCnt[ec-1]->ETURN). WTURN = (w:in->w:readCnt[wc]->w:writeCnt[wc+1]->WTURN | w:out->w:readCnt[wc]->w:writeCnt[wc-1]->WTURN). COUNTER[count] = (readCnt[count]->COUNTER[count] | writeCnt[newCount]->COUNTER[newCount]). PARK = (ETURN || WTURN || COUNTER). Interference E.g., Theme park: • two gates counting entrants • central record of number of people in park Park Does it work? East people West Turnstile Turnstile
Possible state: Possible element of trace: Suppose count = 10 ...->e:read[ec] (ec = 10) ->w:read[wc] (wc = 10) ->w:write[wc+1] (wc+1 = 11 = count) ->e:write[ec+1] (ec+1 = 11 = count) ->… count = 11, but 2 more people in park Interference How? “Does it work?” means “Does it work for all traces?”
An atomic action is an action that executes uninterrupted from start to finish on a processor (In our CSP/FSP notation, events represent atomic actions) Note! Very few statements in a high-level programming language are atomic E.g., assignment is not atomic Java: x = 10; Assembler: LOAD R1 10 LOAD R2 ADDR_X STORE @R2 R1 Atomic Actions
Interference bugs are extremely difficult to track General solution: Identify the critical section of the code Ensure only one process is allowed to execute during its critical section The critical sections are the accesses to the shared memory/resource Mutually exclusive access to critical section through locking LOCK = (acquire->release->LOCK). ETURN = (e:in->INC->ETURN | e:out->DEC->ETURN). INC = (acquire->read[x]->write[x+1]->release). DEC = (acquire->read[x]->write[x-1]->release). COUNTER[count] = (read[count]->COUNTER[count] | write[newCount]->COUNTER[newCount]). Interference and Mutual Exclusion
Keyword synchronized Attached to method: system ensures method executes to completion with no interleaving Can also be attached to an object: synchronized (object) { // code } Object object is locked for duration of code code cannot be executed if another process has the lock on object class Counter { … public synchronized void increment( ) { count++; } } Locking in Java or class Turnstile { Counter counter; … public void enter( ) { synchronized(counter) { counter.increment(); } } } // Remember! Locks object
Locking (synchronisation) limits the number of possible traces to the safe ones If not used carefully, locking will force the system into a sequential execution E.g., the theme park: e:in->INC->w:in->INC->e:in->INC->… One technique to improve concurrency in many systems is buffering Don’t lock the central object Have each thread communicate with central control through its own buffer buffer is a list (e.g., a Vector) buffers are locked for adding and removing, but while doing other work, processes are concurrent Buffering
Synchronisation (and locking) someone must be controlling the locks processes will be waiting to access locked objects Who is controlling? Where do processes wait? A Monitor is a method of managing synchronisation A Monitor provides encapsulation of data and methods mutually exclusive execution of monitored methods condition synchronisation a wait queue of processes waiting to use the monitored resources Monitors
Java provides support for treating any object as a monitor (through keyword synchronized) Typical usage scenario Active entities (initiating actions) implemented as threads Passive entities (responding to actions) controlling shared resources implemented as monitors Condition synchronisation: Java provides a wait queue per object: final void wait() throws InterruptedException puts thread on wait queue thread releases synchronisation lock on monitor thread waits until notified by another thread when awoken, thread must still wait to reacquire synchronisation lock on monitor final void notify() wake up a single thread on the wait queue final void notifyAll() wake up all threads on the wait queue Monitors
Carpark cars can enter carpark when it’s not full cars can leave carpark when it’s not empty Processes arrivals departures controller CONTROL[spaces] = ( when (spaces > 0) arrive -> CONTROL[spaces-1] | when (spaces < MAX) depart -> CONTROL[spaces+1] ). ARRIVALS = (arrive -> ARRIVALS). DEPARTURES = (depart -> DEPARTURES). ||CARPARK = ( CONTROL || ARRIVALS || DEPARTURES). Monitor and Condition Synchronisation Example Implementation: • ARRIVALS and DEPARTURES: threads • CONTROL: monitor
Typical Implementation of Condition Synchronisation CSP/FSP: when cond act -> NEWSTATE Java: public synchronized void act( ) throws InterruptedException { while (!cond) wait( ); // modify monitor state notifyAll( ); } Notification necessary to awaken threads that may be waiting to enter the monitor now that its state has changed
class Arrivals implements Runnable { protected CarParkControl carpark; public Arrivals(CarParkControl c) { carpark = c; } public void run() { try { while (true) { carpark.arrive(); // delay } } catch (InterruptedException e) {} } class CarParkControl { protected int spaces; protected int capacity; … public synchronized void arrive() throws InterruptedException { while (spaces==0) wait(); spaces - -; notify(); } public synchronized void depart() throws InterruptedException { while (spaces==capacity) wait(); spaces++; notify(); } } Carpark in Java