-
Notifications
You must be signed in to change notification settings - Fork 205
/
Copy pathReadersWriters.tla
123 lines (93 loc) · 3.33 KB
/
ReadersWriters.tla
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
-------------------------- MODULE ReadersWriters --------------------------
(***************************************************************************)
(* This solution to the readers-writers problem, cf. *)
(* https://en.wikipedia.org/wiki/Readers–writers_problem, *)
(* uses a queue in order to fairly serve all requests. *)
(***************************************************************************)
EXTENDS FiniteSets, Naturals, Sequences
CONSTANT NumActors
VARIABLES
readers, \* set of processes currently reading
writers, \* set of processes currently writing
waiting \* queue of processes waiting to access the resource
vars == <<readers, writers, waiting>>
Actors == 1..NumActors
ToSet(s) == { s[i] : i \in DOMAIN s }
read(s) == s[1] = "read"
write(s) == s[1] = "write"
WaitingToRead == { p[2] : p \in ToSet(SelectSeq(waiting, read)) }
WaitingToWrite == { p[2] : p \in ToSet(SelectSeq(waiting, write)) }
---------------------------------------------------------------------------
(***********)
(* Actions *)
(***********)
TryRead(actor) ==
/\ actor \notin WaitingToRead
/\ waiting' = Append(waiting, <<"read", actor>>)
/\ UNCHANGED <<readers, writers>>
TryWrite(actor) ==
/\ actor \notin WaitingToWrite
/\ waiting' = Append(waiting, <<"write", actor>>)
/\ UNCHANGED <<readers, writers>>
Read(actor) ==
/\ readers' = readers \union {actor}
/\ waiting' = Tail(waiting)
/\ UNCHANGED writers
Write(actor) ==
/\ readers = {}
/\ writers' = writers \union {actor}
/\ waiting' = Tail(waiting)
/\ UNCHANGED readers
ReadOrWrite ==
/\ waiting /= <<>>
/\ writers = {}
/\ LET pair == Head(waiting)
actor == pair[2]
IN CASE pair[1] = "read" -> Read(actor)
[] pair[1] = "write" -> Write(actor)
StopActivity(actor) ==
IF actor \in readers
THEN /\ readers' = readers \ {actor}
/\ UNCHANGED <<writers, waiting>>
ELSE /\ writers' = writers \ {actor}
/\ UNCHANGED <<readers, waiting>>
Stop == \E actor \in readers \cup writers : StopActivity(actor)
---------------------------------------------------------------------------
(*****************)
(* Specification *)
(*****************)
Init ==
/\ readers = {}
/\ writers = {}
/\ waiting = <<>>
Next ==
\/ \E actor \in Actors : TryRead(actor)
\/ \E actor \in Actors : TryWrite(actor)
\/ ReadOrWrite
\/ Stop
Fairness ==
/\ \A actor \in Actors : WF_vars(TryRead(actor))
/\ \A actor \in Actors : WF_vars(TryWrite(actor))
/\ WF_vars(ReadOrWrite)
/\ WF_vars(Stop)
Spec == Init /\ [][Next]_vars /\ Fairness
---------------------------------------------------------------------------
(**************)
(* Invariants *)
(**************)
TypeOK ==
/\ readers \subseteq Actors
/\ writers \subseteq Actors
/\ waiting \in Seq({"read", "write"} \times Actors)
Safety ==
/\ ~(readers /= {} /\ writers /= {})
/\ Cardinality(writers) <= 1
(**************)
(* Properties *)
(**************)
Liveness ==
/\ \A actor \in Actors : []<>(actor \in readers)
/\ \A actor \in Actors : []<>(actor \in writers)
/\ \A actor \in Actors : []<>(actor \notin readers)
/\ \A actor \in Actors : []<>(actor \notin writers)
============================================================================