Skip to content

Commit b0bbddc

Browse files
committed
v29 (Starvation): Advanced fairness ruling out starvation entirely.
1 parent bd2d57c commit b0bbddc

File tree

2 files changed

+34
-3
lines changed

2 files changed

+34
-3
lines changed

BlockingQueue.tla

+29-3
Original file line numberDiff line numberDiff line change
@@ -116,12 +116,38 @@ MCIInv == TypeInv!1 /\ IInv
116116

117117
PutEnabled == \A p \in Producers : ENABLED Put(p, p)
118118

119-
FairSpec == Spec /\ WF_vars(Next)
120-
/\ \A p \in Producers : WF_vars(Put(p, p))
119+
FairSpec ==
120+
/\ Spec
121+
122+
\* Assert that producers take steps should their Put action be (continuously)
123+
\* enabled. This is the basic case of fairness that rules out stuttering, i.e.,
124+
\* assert global progress.
125+
/\ \A t \in Producers:
126+
WF_vars(Put(t,t))
127+
\* Stipulates that Get actions (consumers!) will eventually notify *all*
128+
\* waiting producers. In other words, given repeated Get actions (we don't
129+
\* care which consumer, thus, existential quantification), all waiting
130+
\* producers will eventually be notified. Because Get actions are not
131+
\* continuously enabled (the buffer might be empty), weak fairness is not
132+
\* strong enough. Obviously, no real system scheduler implements such an
133+
\* inefficient "policy".
134+
\* This fairness constraint was initially proposed by Leslie Lamport, although
135+
\* with the minor typo "in" instead of "notin", which happens to hold for
136+
\* configurations with at most two producers.
137+
/\ \A t \in Producers:
138+
SF_vars(\E self \in Consumers: Get(self) /\ t \notin waitSet')
139+
140+
\* See notes above (except swap "producer" with "consumer").
141+
/\ \A t \in Consumers:
142+
WF_vars(Get(t))
143+
/\ \A t \in Consumers:
144+
SF_vars(\E self \in Producers: Put(self, self) /\ t \notin waitSet')
121145

122146
(* All producers will continuously be serviced. For this to be violated, *)
123147
(* ASSUME Cardinality(Producers) > 1 has to hold (a single producer cannot *)
124148
(* starve itself). *)
125-
Starvation == \A p \in Producers: []<>(<<Put(p, p)>>_vars)
149+
Starvation ==
150+
/\ \A p \in Producers: []<>(<<Put(p, p)>>_vars)
151+
/\ \A c \in Consumers: []<>(<<Get(c)>>_vars)
126152

127153
=============================================================================

README.md

+5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ This tutorial is work in progress. More chapters will be added in the future. In
1313

1414
--------------------------------------------------------------------------
1515

16+
### v29 (Starvation): Advanced fairness ruling out starvation entirely.
17+
18+
Stipulates that `Get` actions (consumers!) will eventually notify *all* waiting producers. In other words, given repeated `Get` actions (we don't care which consumer, thus, existential quantification), all waiting producers will eventually be notified. Because `Get` actions are not continuously enabled (the buffer might be empty), weak fairness is not strong enough. Obviously, no real system scheduler implements such an inefficient "policy".
19+
This fairness constraint was initially proposed by Leslie Lamport (with the minor typo "in" instead of "notin", which happens to hold for configurations with at most two producers).
20+
1621
### v28 (Starvation): Weak fairness defined for Put.
1722

1823
Defining ```Next``` to be (weakly) [fair](https://pron.github.io/posts/tlaplus_part3#machine-closure-and-fairness) makes only sure that a Next-step is (eventually) taken. However, ```Next``` is a disjunct of the ```Put``` and ```Get``` sub-actions and fairness does not distribute. Since, we want all producers to eventually take steps, we specify (weak) fairness at the level of the ```Put``` sub-actions. Unfortunately, producers can still starve:

0 commit comments

Comments
 (0)