Concurrencysynchronization using UML state models April 14 th

  • Slides: 21
Download presentation
Concurrency/synchronization using UML state models April 14 th, 2008 Michigan State University

Concurrency/synchronization using UML state models April 14 th, 2008 Michigan State University

Overview State models of monitor objects n n n Monitor-process pattern Heuristic for “generating”

Overview State models of monitor objects n n n Monitor-process pattern Heuristic for “generating” correct synchronization code from a state model Use of signal vs. broadcast to notify waiting threads Examples Synchronization that is more difficult to model using state diagrams

Method for using models to design concurrent software State model for each system object

Method for using models to design concurrent software State model for each system object n Passive objects modeled using monitor-process pattern Models then refined into code skeletons n Active objects incorporate infrastructure needed to host a thread: w E. g. , a distinguished run method whose activation corresponds to the lifetime of a thread n Passive objects designed to behave as monitors w Design pattern for passive-object model guarantees monitor-object pattern can be applied to develop code w Guarded transitions in state model engender condition synchronization in code

Simple monitor-process pattern Simple pattern: n n Distinguished initial state Idle Composite state for

Simple monitor-process pattern Simple pattern: n n Distinguished initial state Idle Composite state for each monitor operation w Reachable only from Idle via an accept-call action n n Entry is named according to the name of the operation Possibly guarded with an enabling condition w Must transition back to Idle via a reply action upon exit n n Names the entry to which it corresponds Includes return value (if any) w No accept-call actions within the composite state Variations on this pattern will relax some of these restrictions

Simple monitor-process pattern Monitor process / reply (op, result ) Idle [guard] / accept-call

Simple monitor-process pattern Monitor process / reply (op, result ) Idle [guard] / accept-call ( op(parms) ) Operation body

Bounded Buffer Example Bounded. Buffer Pulling [queue_. size != 0] / accept-call ( pull

Bounded Buffer Example Bounded. Buffer Pulling [queue_. size != 0] / accept-call ( pull ) do/ rv : = queue_. pull / reply ( pull, rv ) Idle / reply ( push ) [queue_. size != MAX] / accept-call ( push(x) ) Pushing do/ queue_. push(x)

From simple monitor process to monitor object (code) Class declares a private mutex variable

From simple monitor process to monitor object (code) Class declares a private mutex variable lock Each operation state in the model becomes a monitor method in the code n Method body bracketed by acquire/release of lock If any transition out of Idle is guarded: n Class must declare a condition variable, associated with lock, to wait on when guard condition is NOT satisfied Method body includes a condition wait loop immediately following acquisition of lock All other methods must notify this condition variable if they might serve to satisfy this guard condition Notification could be signal or broadcast

Example: Code for Buffer: : push [queue_. size() != MAX] / accept-call (push(x)) void

Example: Code for Buffer: : push [queue_. size() != MAX] / accept-call (push(x)) void Buffer: : push(int x) { lock_. acquire(); while (queue_. size() == MAX) { full_. wait(); } queue_. push(x); empty_. signal(); lock_. release(); } Idle / reply (push) Pushing do/ queue_. push(x)

Example: Code for Buffer: : push [queue_. size() != MAX] / accept-call (push(x)) void

Example: Code for Buffer: : push [queue_. size() != MAX] / accept-call (push(x)) void Buffer: : push(int x) { lock_. acquire(); while (queue_. size() == MAX) { full_. wait(); } queue_. push(x); empty_. signal(); lock_. release(); } Idle / reply (push) Pushing do/ queue_. push(x)

Example: Code for Buffer: : push [queue_. size() != MAX] / accept-call (push(x)) void

Example: Code for Buffer: : push [queue_. size() != MAX] / accept-call (push(x)) void Buffer: : push(int x) { lock_. acquire(); while (queue_. size() == MAX) { full_. wait(); } queue_. push(x); empty_. signal(); lock_. release(); } Idle / reply (push) Pushing do/ queue_. push(x)

Example: Code for Buffer: : push [queue_. size() != MAX] / accept-call (push(x)) void

Example: Code for Buffer: : push [queue_. size() != MAX] / accept-call (push(x)) void Buffer: : push(int x) { lock_. acquire(); while (queue_. size() == MAX) { full_. wait(); } queue_. push(x); empty_. signal(); lock_. release(); } Idle / reply (push) Pushing do/ queue_. push(x)

Example: Code for Buffer: : pull [queue_. size() != 0] / accept-call (pull) int

Example: Code for Buffer: : pull [queue_. size() != 0] / accept-call (pull) int Buffer: : pull() { lock_. acquire(); while (queue_. size() == 0) { empty_. wait(); } int rv = queue_. pull(); full_. signal(); lock_. release(); return rv; } Idle / reply (pull, rv) Pushing do/ rv : = queue_. pull()

More complex guard conditions Consider a banking application that allows multiple clients to deposit

More complex guard conditions Consider a banking application that allows multiple clients to deposit and withdraw funds from shared accounts Goals: n n Protect against data races, so that money is not accidentally created or destroyed Prevent overdrafts by making withdraw requests block if account has insufficient funds Question: How should we model the behavior of an account object?

Monitor-process model of Bank. Account Depositing / accept-call ( deposit(amount) ) do/ balance_ +=

Monitor-process model of Bank. Account Depositing / accept-call ( deposit(amount) ) do/ balance_ += amount; / reply ( deposit ) Idle / reply ( withdraw ) [ amount <= balance_ ] / accept-call ( withdraw(amount) ) Withdrawing do/ balance_ -= amount;

Code for Bank. Account: : withdraw [amount <= balance_] / accept-call (withdraw(amount)) void Bank.

Code for Bank. Account: : withdraw [amount <= balance_] / accept-call (withdraw(amount)) void Bank. Account: : withdraw(int amount) { lock_. acquire(); while (amount > balance_) { ok. To. Withdraw_. wait(); } balance_ -= amount; lock_. release(); } Idle / reply (withdraw) Withdrawing do/ balance_ -= amount;

Code for Bank. Account: : deposit / accept-call (deposit(amount)) void Bank. Account: : deposit(int

Code for Bank. Account: : deposit / accept-call (deposit(amount)) void Bank. Account: : deposit(int amount) { lock_. acquire(); balance_ += amount; ok. To. Withdraw_. broadcast(); lock_. release(); } Idle / reply (deposit) Depositing do/ balance_ += amount;

Signal vs. Broadcast When one thread changes the value of a condition upon which

Signal vs. Broadcast When one thread changes the value of a condition upon which others might be waiting, the modifier is obliged to notify these waiting threads Always safest, though perhaps not very efficient, to use broadcast to notify waiting threads after a change Question: When is it safe to use signal?

More complex monitors… Simple monitor-process pattern insufficient for handling some forms of synchronization n

More complex monitors… Simple monitor-process pattern insufficient for handling some forms of synchronization n n E. g. , barriers, using which two or more threads must arrive before either may pass Not so easily modeled using guarded transitions May require: n n Embedding accept-call actions involving other operations within an operation state Explicit modeling, storage, and retrieval of request objects associated with calls into an entry

Party-admission problem Models the admission of (boy–girl) couples to a party n n n

Party-admission problem Models the admission of (boy–girl) couples to a party n n n Boys and girls arrive independently but are blocked from entering the party except as couples When a boy arrives, he must block unless and until a girl has arrived for him to hook up with Example of something called a barrier synchronization Requires embedding accept-call action for girl. Arrives inside operation state for boy. Arrives and vice versa n n Violates our simple monitor-process conventions Still, may be modeled without too much trouble and without any use of guards on transitions

Example: Part of the model Boy. Waiting / accept-call (girl. Arrives) Idle / accept-call

Example: Part of the model Boy. Waiting / accept-call (girl. Arrives) Idle / accept-call (boy. Arrives) Boy. Meets. Girl / reply (girl. Arrives) / reply (boy. Arrives)

Example: Other part of the model Girl. Waiting / accept-call (boy. Arrives) Idle /

Example: Other part of the model Girl. Waiting / accept-call (boy. Arrives) Idle / accept-call (girl. Arrives) Boy. Meets. Girl / reply (boy. Arrives) / reply (girl. Arrives)