2sd3 Final
2sd3 Final
2 – The Triumph of Bureaucracy and Vocal Minority: You Shall (Not) Pass Edition
If you’re reading this, please contribute! Petri Nets Nested Monitor Problem ||RESOURCES = ({s_m,s_p}::TOBACCO || {s_t,s_m}::
Reachability Graphs ,→ PAPER || {s_t,s_p}::MATCH ).
REMINDER! This is a template! The cheat sheet P/T nets ||AGENT_RULE = ({s_m,s_p,s_t}::RULE || {s_m,s_p}::
maintainer (.json) intentionally leaves extra space
for you to add your own notes! If something’s Each place in a P/T net can hold multiple ,→ AGENT_T || {s_m,s_t}::AGENT_P ||
missing, add it yourself! (and if it’s important tokens. Each transition has a weight, w, {s_t,s_p}::AGENT_M ).
enough please contribute!) associated with it. If it is an input transition, ||CIG_SMOKERS = (SMOKERS || RESOURCES ||
firing takes w tokens from the input place. If its ,→ AGENT_RULE)/
an output transition, firing adds w tokens to the {s_t.get_paper/s_t.picked,
FSP output place. An action can only be fired if s_m.get_paper/s_m.picked,
enough input tokens are present in all input s_p.get_paper/s_p.picked,
Syntax s_t.deliver_paper/s_t.delivered,
s_m.deliver_paper/s_m.delivered,
s_p.deliver_paper/s_p.delivered,
// instance prefixing - a:P s_t.smoking_completed/s_t.smoke_cigarrette,
SWITCH = (on -> off -> SWITCH). s_m.smoking_completed/s_m.smoke_cigarrette,
||TWO_SWITCH = (a:SWITCH || b:SWITCH). s_p.smoking_completed/s_p.smoke_cigarrette}.
// relabeling - /{new1/old1, new2/old2, ...}.
CLIENT = (call -> wait -> continue -> CLIENT).
SERVER = (request -> service -> reply -> SERVER).
||CLIENT_SERVER = (CLIENT||SERVER)/{call/request, Property (safety)
,→ reply/wait}.
// process prefixing (mutex) - {a1, ..., ax} :: P
RESOURCE = (acquire -> release -> RESOURCE).
Hiding/Labeling property CORRECT_PICKUP =
colour PH = with ph1 | ph2 | ph3 | ph4 | ph5
USER = (acquire -> user -> release -> USER). relabeling: places. (s_t.get_paper->s_t.get_match->CORRECT_PICKUP
colour Fork = with f1 | f2 | f3 | f4 | f5 |s_p.get_tobacco->s_p.get_match->CORRECT_PICKUP
||RESOURCE_SHARE = (a:USER || b:USER || {a, b}:: (PROCESS)/{newlabel1/oldlabel1, ..., newlabeln/oldlabeln} LEFT : PH -> FORK, RIGHT : PH -> FORK
,→ RESOURCE). interface: (PROCESS)@{a1...ax} hides all Deadlocks var x : PH |s_m.get_tobacco->s_m.get_paper->CORRECT_PICKUP).
// RESOURCE is a single shared instance between actions except a1 . . . ax fun LEFT x = case of ph1 => f2 | ph2 => f3 | ph3
,→ the two USERs
hiding: (PROCESS) \{a1...an} hides actions
Dining Philosophers Problem ,→ => f4 | ph4 => f5 | ph5 => f1
// for loop syntax
|| SWITCHES (N = 3) = (forall [i:1..N] s[i]:SWITCH a1...an Simple minded construction: fun RIGHT x = case of ph1 => f1 | ph2 => f2 | ph3
{a1, ..., ax} :: P replaces every action label n in ,→ => f3 | ph4 => f4 | ph5 => f5 Ask first, do later
,→ )
// or alternatively the alphabet of P with the labels a1.n, ... , ax.n.
FORK = (get -> put -> FORK).
range Seats = 1..3 Thus, every transition (n → X) in the definition PHIL = (think -> right.get -> left.get -> eat ->
|| SEATS=(seat[i:1..3]:SEAT). of P is replaced with the transitions ,→ right.put -> left.put -> PHIL). Semaphores and Extensions SMOKER_T=( no_tobacco -> get_paper -> get_match->
({a1.n, ..., ax.n} →− X) ||DINERS(N = 5) = forall[i : 1..N] (phil[i] : PHIL ,→ roll_cigarrette ->
// hiding operator - \{a1, ..., ax} Dijkstra’s Semaphore Operations smoke_cigarrette -> SMOKER_T)
// interface operator - @{a1, ..., ax} ,→ || {phil[i].right, phil[(i % 5) + 1].
// these two do the same thing Bisimulation ,→ left} :: FORK C(s) – initial value of a semaphore variable s SMOKER_P=( no_paper -> get_tobacco -> get_match->
USER = (acquire -> use -> release -> USER)\{use}. State Bisimilarity – p ≈ q iff whatever action ndown(s) – number of times down(s) was ,→ roll_cigarrette ->
USER = (acquire -> use -> release -> USER)@{ executed at p can also be executed at q, and vice smoke_cigarrette -> SMOKER_P)
executed nup(s) – number of times up(s) was SMOKER_M=( no_match -> get_tobacco -> get_paper->
,→ acquire, release}. versa. Solution 1 – Add asymmetry into the executed npdown(s) – number of times down(s) ,→ roll_cigarrette ->
// syntax for progress LTS Bisimilarity – P ≈ Q iff each state pt , composition, where 1, 3, 5 always perform was passed smoke_cigarrette -> SMOKER_T)
progress P = {a1, ..., an} reachable from the initial state by a trace t in P ‘left.get -> right.get’, while 2, 4 always perform
is bisimilar to an appropriate state qt that is Then we define down and up: TOBACCO = ( delivered -> picked -> TOBACCO )
// syntax for high priority ‘right.get -> left.get’. PAPER = ( delivered -> picked -> PAPER )
reachable from the initial state by the same trace down(s): ndown(s) = ndown(s)+1: if ndown(s)
||C = (P||Q)<<{a1, ..., an}.
t in Q. <= nup(s) + C(s) then npdown(s) = npdown(s) MATCH = ( delivered -> picked -> MATCH )
// syntax for low priority PHIL = (when(i=1|i=3|i=5) think -> left.get -> + 1; AGENT_T = (can_deliver -> no_tobacco ->
||C = (P||Q)>>{a1, ..., an}. ,→ right.get -> eat -> left.put -> right. ,→ deliver_paper->deliver_match->AGENT_T)
Mutual Exclusion ,→ put -> PHIL
up(s): if ndown(s) > nup(s) + C(s) then AGENT_P = (can_deliver -> no_paper ->
// simulating a boolean Arbitrary interleaving of read and write actions npdown(s) = npdown(s) + 1; nup(s) = nup(s)+1; ,→ deliver_match->deliver_tobacco->AGENT_P
const False = 0 |when(i=2|i=4) think -> right.get -> left. ,→ )
const True = 1 leads to interference. Interference bugs are ,→ get -> eat -> right.put -> left.
difficult to locate. We use mutual exclusion to Theorem 1. npdown(s) = min(ndown(s), C(s) + AGENT_M = (can_deliver -> no_match ->
range Bool = 0..1 ,→ put -> PHIL). ,→ deliver_tobacco->deliver_paper->AGENT_M
only give one process access to the shared nup(s))
resource at a time. ,→ )
RULE = (can_deliver -> smoking_completed -> RULE )
Solution 2 – Use a butler to prevent more than 4
Maker-user example LOCK = (acquire->release->LOCK). philosophers from sitting at the table. Multidimensional Semaphores of SMOKERS = s_t:SMOKER_T || s_p:SMOKER_P || s_m:
U1 = (acquire -> use -> release -> U1). Agerwala ,→ SMOKER_M
MAKER = (make -> ready -> MAKER). U2 = (acquire -> use -> release -> U2). RESOURCES = {s_m,s_p}::TOBACCO || {s_t,s_m}::PAPER
||SYSTEM = (u1:U1||u2:U2||{u1,u2}::LOCK). PHIL = (think -> sitdown -> right.get -> left.get edown(s1, . . . , sn , sn+1 , . . . , sn+m : if for all ,→ || {s_t,s_p}::MATCH
USER = (ready -> user -> USER). ,→ -> eat -> right.put -> left.put ->
||MAKER_USER = (MAKER || USER). i, 1 ≤ i ≤ n, si > 0 and for all AGENT_RULE = {s_m,s_p,s_t}::RULE || {s_m,s_p}::
,→ getup -> PHIL).
Above allows for lock− →use−→release for either BUTLER(K=4) = COUNT[0], j, 1 ≤ j ≤ m, Sn+j = 0 then for all ,→ AGENT_T || {s_m,s_t}::AGENT_P || {s_t,
user but only one of them at a time. COUNT[i:1..4] = (when(i<K) sitdown -> COUNT[i+1] | i, 1 ≤ i ≤ n, si = si − 1 else block execution of ,→ s_p}::AGENT_M
Garden example (maybe move this to a diff ,→ getup -> COUNT[i-1]). calling processes CIG_SMOKERS = (SMOKERS || RESOURCES || AGENT_RULE)
section later)
Monitors and Semaphores ||DINERS(N=5) ... eup(s1 , s2 , . . . , sn : if processes blocked on ,→ /
Monitor – A threadsafe class where each ||{phil[i:1..N]}::BUTLER(K=4)). (s1 , . . . , sn ) then awaken al of them else for all {s_t.get_paper/s_t.picked,
function is wrapped by a mutex. Essentially, only s_m.get_paper/s_m.picked,
i, i ≤ i ≤ n, si = si + 1 s_p.get_paper/s_p.picked,
const N = 4 one process may access the class at a time.
range T = 0..N Entirely syntactic sugar. Semaphore – Solution 3 – Use Simultaneity s_t.deliver_paper/s_t.delivered,
set VarAlpha = {value.{read[T],write[T]}}
Inhibitor Nets s_m.deliver_paper/s_m.delivered,
Essentially a mutex with a queue of processes Add a circle to the transition side of an arc to
VAR = VAR[0], s_p.deliver_paper/s_p.delivered,
make it an inhibitor arc Now the transition can s_t.smoking_completed/s_t.smoke_cigarrette,
VAR[u:T] = (read[u] ->VAR[u] down(s): if s > 0 then only be fired if the places connected by inhibitor
|write[v:T]->VAR[v]). arcs are empty. s_m.smoking_completed/s_m.smoke_cigarrette,
decrement s s_p.smoking_completed/s_p.smoke_cigarrette}.
TURNSTILE = (go -> RUN), else
RUN = (arrive-> INCREMENT block execution of calling process Smokers’ Problem
|end -> TURNSTILE), up(s): if processes blocked on s then 3 Smokers each have an unlimited type of either
awaken one of them tobacco, cigarette paper, matches. 2 ingredients
INCREMENT = (value.read[x:T] else
->value.write[x+1]->RUN) increment s are placed on the table, the smoker with the third Safety and Liveness
+VarAlpha. ingredient needed should pick up the ingredients,
DISPLAY =(value.read[T]->DISPLAY)+{value.write[T make a cigarette, and smoke it. Next set of Safety – asserts that nothing bad happens
,→ ]}. ingredients won’t be placed until smoking is
const Max = 3 completed. Safety Property P – defines a process that
||GARDEN = (east:TURNSTILE || west:TURNSTILE || range Int = 0..Max asserts any trace including the actions in the
,→ display:DISPLAY SEMAPHORE(N=0) = SEMA[N], Simple-minded Solution alphabet of P is accepted by P , otherwise they
|| {east,west,display}::value:VAR) SEMA[v:Int] = (up->SEMA[v+1] are transitions to the ERROR state, safety checks
/{go /{east,west}.go, |when(v>0) down->SEMA[v-1] are compositional hence they should be composed
end/{east,west}.end}. ). SMOKER_T=( get_paper -> get_match->roll_cigarrette
,→ -> smoke_cigarrette -> SMOKER_T). with the appropriate (sub)system
LOOP = (mutex.down -> critical -> mutex.up -> LOOP SMOKER_P=( get_tobacco -> get_match->
,→ ). ,→ roll_cigarrette -> smoke_cigarrette -> Liveness – asserts that something good
||SEMADEMO = (p[1..3]:LOOP || {p[1..3]}::mutex: ,→ SMOKER_P). eventually happens
LTS ,→ SEMAPHORE(1)). SMOKER_M=( get_tobacco -> get_paper->
,→ roll_cigarrette -> smoke_cigarrette -> Progress Property – asserts that it is always
,→ SMOKER_M). the case that a particular action is eventually
executed, opposite of starvation, progress checks
Bounded Buffer TOBACCO = ( delivered -> picked -> TOBACCO ).
PAPER = ( delivered -> picked -> PAPER ). are not compositional hence they should be
A buffer with a fixed number of slots MATCH = ( delivered -> picked -> MATCH ). conducted after safety checks
BUFFER(N=5) = COUNT[0], AGENT_T = (can_deliver -> deliver_paper -> Starvation – situation in which an action is
COUNT[i:0..N] Only fire a transition if both forks are available ,→ deliver_match -> AGENT_T ). never executed
= (when (i<N) put->COUNT[i+1] AGENT_P = (can_deliver -> deliver_match -> Terminal Set of States – set of states in which
,→ deliver_tobacco -> AGENT_P ).
|when (i>0) get->COUNT[i-1]
).
Coloured Petri Nets AGENT_M = (can_deliver -> deliver_tobacco ->
every state is reachable from every other state in
the set and there is no transition from within to
PRODUCER = (put->PRODUCER). “Colours” are simply types of tokens that are ,→ deliver_paper -> AGENT_M ). set to any state outside the set
CONSUMER = (get->CONSUMER). passed around the petri net Paths to transitions RULE = (can_deliver -> smoking_completed -> RULE )
,→ . Priority – specifies actions that have a
||BOUNDEDBUFFER = (PRODUCER||BUFFER(5)||CONSUMER). are either labeled with variables or functions that
transform one of the input variables into the ||SMOKERS = (s_t:SMOKER_T || s_p:SMOKER_P || s_m: higher/lower priority than any other action in the
object to remove from a state. ,→ SMOKER_M ). alphabet of some state
CTL and LTL For the above FSPs, they both share the same Properties Two Warring Neighbours A3Q2 - Gas Question
CTL LTS diagram (LTS version of the right petri net), With properties, whenever you add more Model this algorithm for two neighbours n1 and
A: along all paths however, since ||S1 has simultaneous actions, its transitions through alphabet extension, you need n2. Specified the required safety properties for const N = 3 //number of customers
E: exists a path petri net will be show simultaneity whereas S2 to apply this transition to every state and use it the field and check that it does indeed ensure const M = 2 //number of pumps
X: next state will not. as a transition to an error state. mutually exclusive access. Specify the required range C = 1..N
F: some future state progress properties for the neighbours such that range P = 1..M
G: all future states they both get to pick berries given a fair range A = 1..2 //Amount of money or Gas
U: until (“killer” event must happen) scheduling strategy. CUSTOMER = (prepay[a:A]->gas[x:A]->
W: weak until (“killer” event may never happen). if (x==a) then CUSTOMER else ERROR).
CASHIER = (customer[c:C].prepay[x:A]->start[P][c][
In CTL, must start with path operator (A/E). W const False = 0 ,→ x]->CASHIER).
in CTL: A[p W q] ≡ A[p U q] ∨ AG p (same with const True = 1 PUMP = (start[c:C][x:A] -> gas[c][x]->PUMP).
range Bool = False..True DELIVER = (gas[P][c:C][x:A]->customer[c].gas[x]->
E). set BoolActions = {setTrue, setFalse, [False], [ ,→ DELIVER).
Common Pattenrs AXϕ - in every next state. ,→ True]}
BOOLVAR = VAL[False], ||STATION = (CASHIER || pump[1..M]:PUMP || DELIVER
EXϕ - in some next state.
VAL[v:Bool] = (setTrue -> VAL[True] ,→ )
AGϕ - All computation paths beginning with s /{pump[i:1..M].start/start[i],
|setFalse -> VAL[False]
the property ϕ holds Globally.
EGϕ - There Exists a path beginning in s such
Tut 6 Mutex Example |[v] -> VAL[v]
pump[i:1..M].gas/gas[i]}.
||GASSTATION = (customer[1..N]:CUSTOMER ||STATION)
that ϕ holds Globally along the path. Workers in an office share a printer. The printer ). ,→ .
AF ϕ - For All computation paths beginning with is able to print any number of jobs before it runs ||FLAGS = (flag1:BOOLVAR || flag2:BOOLVAR). // part b
s there will be some Future state where ϕ holds. Q5 - Midterm out of toner. This is replaced by a technician NEIGHBOUR1 = (flag1.setTrue -> TEST), range T = 1..2
EF ϕ - There Exists a computation bath when necessary. TEST = (flag2[b:Bool] -> property FIFO = (customer[i:T].prepay[A] -> PAID[i
A central computer is connected to remote
beginning in s such that ϕ holds in some Future terminals, with seats for concert hall. Clients
if(b) then ,→ ]),
states. (flag1.setFalse -> NEIGHBOUR1) PAID[i:T] = (customer[i].gas[A] -> FIFO
choose a free seat and clerk enters the seat into const J=3 else
A[ϕ1 U ϕ2 ] - All computation paths beginning in s the system and gives a ticket. We need to prevent range Jobs = 0..J |customer[j:T].prepay[A] -> PAID[i][j]),
(enter -> exit -> flag1. PAID[i:T][j:T]= (customer[i].gas[A] -> PAID[j]).
satisfy that ϕ1 Until ϕ2 holds. double booking while letting clients choose any // j Represents toner ,→ setFalse ->
E[ϕ1 U ϕ2 ] - There Exists a computation path available seat. PRINTER = PRINTER [3], ,→ NEIGHBOUR1) ||CHECK_FIFO = (GASSTATION || FIFO).
PRINTER[j: Jobs] = ( when j==0 replace_toner-> )+{{flag1,flag2}.BoolActions}.
beginning in s such that ϕ1 Until ϕ2 holds on it. const False = 0 ,→ PRINTER[J] NEIGHBOUR2 = (flag2.setTrue -> TEST),
The future includes the present. const True = 1
range Bool = False..True
|when j>0 print_job -> PRINTER[j-1]). TEST = (flag1[b:Bool] -> A3Q3 - Cheese Question
USER = (print_job->USER). if(b) then
SEAT = SEAT[False], const M = 2 (flag2.setFalse -> NEIGHBOUR2)
SEAT[reserved:Bool] range Users = 0..M else set Bold = {bold[1..2]}
= ( reserve -> SEAT[True] ||USERS = (forall[i:Users] user [i]:USER). (enter -> exit-> flag2.setFalse -> NEIGHBOUR2) set Meek = {meek[1..2]}
| query[reserved] -> SEAT[reserved] TECHNICIAN=(replace_toner->TECHNICIAN). )+{{flag1,flag2}.BoolActions}. set Customers = {Bold,Meek}
CUSTOMER = (getcheese->CUSTOMER).
| when (reserved) reserve -> ERROR // error ||OFFICE=(USERS||PRINTER||TECHNICIAN) property SAFETY = (n1.enter -> n1.exit -> SAFETY | COUNTER = (getcheese->COUNTER).
,→ of reserved twice /{user[Users].print_job/print_job}. ,→ n2.enter -> n2.exit -> SAFETY). ||CHEESE_COUNTER = (Customers:CUSTOMER ||
). ||FIELD = (n1:NEIGHBOUR1 || n2:NEIGHBOUR2 || {n1, ,→ Customers::COUNTER).
range Seats = 0..1 ,→ n2}::FLAGS || SAFETY).
||SEATS = (seat[Seats]:SEAT).
Equivalences ¬AF ϕ ≡ EG¬ϕ Binary Semaphore Question progress ENTER1 = {n1.enter}
progress ENTER2 = {n2.enter}
LOCK = (acquire -> release -> LOCK).
¬EF ϕ ≡ AG¬ϕ In an operating system, a binary semaphore is ||GREEDY = FIELD<<{{n1,n2}.{flag1,flag2}.setTrue}.
¬AXϕ ≡ EX¬ϕ TERMINAL = (choose[s:Seats] -> acquire used to control access to the console. The console
AF ϕ ≡ A[⊤U ϕ] -> seat[s].query[reserved:Bool] is used by user and system processes. Write down
-> (when(!reserved)seat[s].reserve ->
EF ϕ ≡ E[⊤Iϕ] ,→ release -> TERMINAL a model with FSP for this system. Discuss when
Elevator Example 1 | when(reserved) release -> TERMINAL) user processes may be denied access to the
). console.
“An upwards travelling elevator at the second set Terminals = {a, b}
Burger
floor does not change direction when it has ||CONCERT = (Terminals:TERMINAL || Terminals:: BSEMA = (up -> down -> BSEMA). A cook puts burgers in a pot. A client checks if
passengers wishing to go to the fifth floor” PROCESS = (console.up -> console.down -> PROCESS). there is at least one burger in the pot, and if so,
,→ SEATS || Terminals::LOCK). set Processes = {user[1..2],system[1..2]}
CTL: AG(f loor = 2 ∧ direction = the client must take one.
OS = (Processes:PROCESS || Processes::console: Trace to error: fill[2], c2.check, fill[1], c1.check,
up ∧ ButtonP ressed5 ⇒ A[direction =
up U f loor = 5]). Q7 - Midterm ,→ BSEMA)>>{user}. c2.get, c1.get. Part b change pot to be:
Elevator Example 2 P1 = (a -> b -> c -> P1 | a -> c -> b -> P1). POT = POT[0]
“The elevator can remain idle on the third floor P2 = (a -> (b -> c -> P2 | c -> b -> P2)). Dining Savages POT[p: Burgers] = (when (p>0) check -> get -> POT[
with its doors closed” Q = (b -> c -> Q). ,→ p-1] | fill[n: Burgers] -> POT[n]).
The dining savages: A tribe of savages eats
CTL: AG((f loor = 3 ∧ idle ∧ door = closed) ⇒ ||P1Q = (P1 || Q). communal dinners from a large pot capable of
EG(f loor = 3 ∧ idle ∧ door = closed)) ||P2Q = (P2 || Q). holding M servings of stewed missionaries. When
LTL a savage wants to eat, he helps himself from the
For P1 there are two possible paths which have pot unless it is empty, in which case he waits
⊥ - false, ⊤ - true Other symbols mean the same an a transition. For P2, it starts with one a
as above. A set of paths satisfies ϕ if every path transition, so both the starting states are
until the cook refills the pot. If the pot is empty,
the cook refills the pot with M servings. The
CTL and LTL Examples
in the set satisfies ϕ equivalent in this case. In both branches of P1, behavior of the savages and the cook is described If the process is enabled infinitely often, then it
Equivalences ¬Gϕ ≡ F ¬ϕ you either do b → c → P 1 or c → b → P 1. For by runs infinitely often.
¬F ϕ ≡ G¬ϕ P2, it splits into two possible paths, b → c → P 2 G F enabled ⇒ G F running
¬Xϕ ≡ X¬ϕ or c → b → P 2, which is the same as the traces AG(AF enabled) ⇒ AG(AF running)
F (ϕ ∨ ψ) ≡ F ϕ ∨ F ψ SAVAGE = (get_serving->SAVAGE).
for P1. Therefore P1 and P2 are equivalent. COOK = (fill_pot->COOK). A passenger entering the elevator on 5th floor
G(ϕ ∧ ψ) ≡ Gϕ ∧ Gψ For ||P1Q and ||P2Q,both P1 and Q, and P2 and and pushing 2nd-floor button will never reach 6th
F ϕ ≡ ⊤U ϕ Q, share b → c. In P1 and Q, this becomes a floor, unless 6th-floor button is already lit or
Gϕ ≡ ⊥Rϕ shared action and both P1 and Q will want to use Model the behaviour of the pot and of the system
as FSP processes. somebody will push it, no matter if she/he
ϕU ψ ≡ ϕW ψ ∧ F ψ the same transitions at the same time (deadlock). entered an upwards or upward travelling elevator.
ϕW ψ ≡ ϕU ψ ∨ Gϕ For ||P2Q, the FSP can choose to go in the
ϕW ψ ≡ ψR(ϕ ∨ ψ) const M = 5 AG(f loor = 5 ∧ ButtonP ressed2 ⇒
alternate direction instead of waiting for Q to
ϕRψ ≡ ψW (ϕ ∧ ψ) SAVAGE = (getserving -> SAVAGE). A[¬f loor = 6 U ButtonP ressed6])
finish, so this one would not have a deadlock COOK = (fillpot -> COOK).
whereas ||P1Q will have one.
Dynamic Systems POT = SERVINGS[0],
SERVINGS[i:0..M] = (when (i==0) fillpot ->
Dining Philosophers with ‘atomic
Golf Club Program Alphabet Extension ,→ SERVINGS[M] | when (i>0) getserving -> act of picking up both forks’
golf Processes
,→ SERVINGS[i-1]).
Players at a golf club borrow and then return
balls. Different players need different numbers of P = (a -> b -> P). ||SAVAGES = (SAVAGE || COOK || POT). FORK = ( reserve_right -> take_right -> put_right
balls. How do we model the infinite stream of ,→ -> FORK
Q = (c -> d -> Q). | reserve_left -> take_left -> put_left -> FORK ).
players? We can only model infinite behaviours. Qa = (c -> d -> Q) + {b}.
PHIL = (think -> reserve_forks -> USE_FORKS).
Adverse Scheduling When taking the composition of ||PQ and ||PQa,
Simplified Multidimensional USE_FORKS = ( take_right -> take_left -> eat ->
Intentionally schedule priorities to try to break we take the union of both processes and remove Semaphores ,→ PUT_FORKS
| take_left -> take_right -> eat -> PUT_FORKS ),
things duplicate transitions. In the case of PQ, there are The extended primitives edown and eup are PUT_FORKS = ( put_left -> put_right -> PHIL
Eg for golf club scheduling: no similar transitions, however PQa shares the b atomic (indivisible) and each operates on a set of | put_right -> put_left -> PHIL ).
transition, so that is removed from the LTS. semaphore variables which must be initiated with ||DINERS(N=5) = ( forall[i:1..N]( phil[i]:PHIL ||
progress NOVICE = {NOVICES.get[R]} non-negative integer value. edown(S1,...,Sn): if ,→ {phil[i].right,phil[(i+1)%N].left}::
progress EXPERT = {EXPERTS.get[R]} for all i, 1 ≤ i ≤ n, Si>0 then for all i, ,→ FORK) )
||ProgressCheck = GOLFCLUB >> {Players.put[R]}. 1 ≤ i ≤ n, Si := Si − 1 else block execution of /{
calling processes eup(S1,...,Sn): if processes reserve_forks/right.reserve_right,
reserve_forks/left.reserve_left,
Q7 - A1 blocked on (S1,...,Sn) then awaken one of them reserve_forks_1/reserve_right_1,reserve_forks_1/
else for all i, 1 ≤ i ≤ n, Si := Si + 1 ,→ reserve_left_2,
reserve_forks_2/reserve_right_2,reserve_forks_2/
P = (a -> b -> d -> P). ,→ reserve_left_3,
Q = (c -> b -> e -> Q). SEM(N=INITIAL_VALUE = SEMA[N],
SEMA[v:Int] = (when (v<=Max) up -> SEMA[v+1] | reserve_forks_3/reserve_right_3,reserve_forks_3/
||S1 = (P || Q). ,→ reserve_left_4,
,→ when (v>0) down -> SEMA[v-1]). reserve_forks_4/reserve_right_4,reserve_forks_4/
S2 = (a -> S2A | c -> S2B), SEMS1S2(INITIAL1=3, INITIAL2=3) = (S1:SEM(3) || S2 ,→ reserve_left_5,
S2A = (c -> b -> d -> S2C | c -> b -> e -> S2D), ,→ :SEM(3))\{S1.S2.up/S1.up, S1.S2.up/S2. reserve_forks_5/reserve_right_5,reserve_forks_5/
S2B = (a -> b -> d -> S2C | a -> b -> e -> S2D), ,→ up, S1.S2.down/S1.down, S1.S2.down/S1. ,→ reserve_left_1
S2C = (e -> S2 | a -> e -> S2A), ,→ down}. }.
S2D = (d -> S2 | c -> d -> S2B).