author | nipkow |
Tue, 17 Jun 2025 14:11:40 +0200 | |
changeset 82733 | 8b537e1af2ec |
parent 80073 | 40f5ddeda2b4 |
permissions | -rw-r--r-- |
28578 | 1 |
(* Title: Pure/Concurrent/synchronized.ML |
2 |
Author: Fabian Immler and Makarius |
|
3 |
||
56685 | 4 |
Synchronized variables. |
28578 | 5 |
*) |
6 |
||
7 |
signature SYNCHRONIZED = |
|
8 |
sig |
|
9 |
type 'a var |
|
10 |
val var: string -> 'a -> 'a var |
|
28580 | 11 |
val value: 'a var -> 'a |
68597
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
12 |
val assign: 'a var -> 'a -> unit |
28580 | 13 |
val timed_access: 'a var -> ('a -> Time.time option) -> ('a -> ('b * 'a) option) -> 'b option |
14 |
val guarded_access: 'a var -> ('a -> ('b * 'a) option) -> 'b |
|
28578 | 15 |
val change_result: 'a var -> ('a -> 'b * 'a) -> 'b |
16 |
val change: 'a var -> ('a -> 'a) -> unit |
|
77998 | 17 |
type 'a cache |
18 |
val cache: (unit -> 'a) -> 'a cache |
|
78008 | 19 |
val cache_peek: 'a cache -> 'a option |
80073
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
20 |
val cache_eval: {persistent: bool} -> 'a cache -> 'a |
28578 | 21 |
end; |
22 |
||
23 |
structure Synchronized: SYNCHRONIZED = |
|
24 |
struct |
|
25 |
||
56692 | 26 |
(* state variable *) |
28578 | 27 |
|
68597
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
28 |
datatype 'a state = |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
29 |
Immutable of 'a |
78650
47d0c333d155
clarified signature: retain original Poly/ML names Thread.Thread, Thread.Mutex, Thread.ConditionVar and de-emphasize them for Isabelle/ML;
wenzelm
parents:
78008
diff
changeset
|
30 |
| Mutable of {lock: Thread.Mutex.mutex, cond: Thread.ConditionVar.conditionVar, content: 'a}; |
68597
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
31 |
|
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
32 |
fun init_state x = |
78650
47d0c333d155
clarified signature: retain original Poly/ML names Thread.Thread, Thread.Mutex, Thread.ConditionVar and de-emphasize them for Isabelle/ML;
wenzelm
parents:
78008
diff
changeset
|
33 |
Mutable {lock = Thread.Mutex.mutex (), cond = Thread.ConditionVar.conditionVar (), content = x}; |
68597
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
34 |
|
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
35 |
fun immutable_fail name = raise Fail ("Illegal access to immutable value " ^ name); |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
36 |
|
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
37 |
abstype 'a var = Var of {name: string, state: 'a state Unsynchronized.ref} |
35015
efafb3337ef3
removed slightly adhoc single-assignment feature, cf. structure Single_Assignment;
wenzelm
parents:
33060
diff
changeset
|
38 |
with |
28578 | 39 |
|
68597
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
40 |
fun var name x = |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
41 |
Var {name = name, state = Unsynchronized.ref (init_state x)}; |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
42 |
|
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
43 |
fun value (Var {name, state}) = |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
44 |
(case ! state of |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
45 |
Immutable x => x |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
46 |
| Mutable {lock, ...} => |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
47 |
Multithreading.synchronized name lock (fn () => |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
48 |
(case ! state of |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
49 |
Immutable x => x |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
50 |
| Mutable {content, ...} => content))); |
28578 | 51 |
|
68597
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
52 |
fun assign (Var {name, state}) x = |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
53 |
(case ! state of |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
54 |
Immutable _ => immutable_fail name |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
55 |
| Mutable {lock, cond, ...} => |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
56 |
Multithreading.synchronized name lock (fn () => |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
57 |
(case ! state of |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
58 |
Immutable _ => immutable_fail name |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
59 |
| Mutable _ => |
78720 | 60 |
Thread_Attributes.uninterruptible_body (fn _ => |
68675
4535a45182d5
updated to polyml-5.7.1-7 (see also afa7c5a239e6);
wenzelm
parents:
68597
diff
changeset
|
61 |
(state := Immutable x; RunCall.clearMutableBit state; |
78720 | 62 |
Thread.ConditionVar.broadcast cond))))); |
28580 | 63 |
|
28578 | 64 |
|
65 |
(* synchronized access *) |
|
66 |
||
68597
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
67 |
fun timed_access (Var {name, state}) time_limit f = |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
68 |
(case ! state of |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
69 |
Immutable _ => immutable_fail name |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
70 |
| Mutable {lock, cond, ...} => |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
71 |
Multithreading.synchronized name lock (fn () => |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
72 |
let |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
73 |
fun try_change () = |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
74 |
(case ! state of |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
75 |
Immutable _ => immutable_fail name |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
76 |
| Mutable {content = x, ...} => |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
77 |
(case f x of |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
78 |
NONE => |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
79 |
(case Multithreading.sync_wait (time_limit x) cond lock of |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
80 |
Exn.Res true => try_change () |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
81 |
| Exn.Res false => NONE |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
82 |
| Exn.Exn exn => Exn.reraise exn) |
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
83 |
| SOME (y, x') => |
78720 | 84 |
Thread_Attributes.uninterruptible_body (fn _ => |
68597
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
85 |
(state := Mutable {lock = lock, cond = cond, content = x'}; |
78720 | 86 |
Thread.ConditionVar.broadcast cond; SOME y)))); |
68597
afa7c5a239e6
more frugal assignment of lazy value: fewer mutexes, condvars;
wenzelm
parents:
64276
diff
changeset
|
87 |
in try_change () end)); |
33060
e66b41782cb5
support single-assigment variables -- based on magic RTS operations by David Matthews;
wenzelm
parents:
32738
diff
changeset
|
88 |
|
62918 | 89 |
fun guarded_access var f = the (timed_access var (fn _ => NONE) f); |
28580 | 90 |
|
91 |
||
92 |
(* unconditional change *) |
|
93 |
||
94 |
fun change_result var f = guarded_access var (SOME o f); |
|
28578 | 95 |
fun change var f = change_result var (fn x => ((), f x)); |
96 |
||
35015
efafb3337ef3
removed slightly adhoc single-assignment feature, cf. structure Single_Assignment;
wenzelm
parents:
33060
diff
changeset
|
97 |
end; |
33060
e66b41782cb5
support single-assigment variables -- based on magic RTS operations by David Matthews;
wenzelm
parents:
32738
diff
changeset
|
98 |
|
77998 | 99 |
|
100 |
(* cached evaluation via weak_ref *) |
|
101 |
||
80073
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
102 |
local |
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
103 |
|
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
104 |
datatype 'a cache_state = |
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
105 |
Undef |
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
106 |
| Value of 'a |
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
107 |
| Weak_Ref of 'a Unsynchronized.weak_ref; |
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
108 |
|
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
109 |
fun peek Undef = NONE |
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
110 |
| peek (Value x) = SOME x |
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
111 |
| peek (Weak_Ref r) = Unsynchronized.weak_peek r; |
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
112 |
|
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
113 |
fun weak_active (Weak_Ref r) = Unsynchronized.weak_active r |
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
114 |
| weak_active _ = false; |
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
115 |
|
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
116 |
in |
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
117 |
|
77998 | 118 |
abstype 'a cache = |
80073
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
119 |
Cache of {expr: unit -> 'a, var: 'a cache_state var} |
77998 | 120 |
with |
121 |
||
122 |
fun cache expr = |
|
80073
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
123 |
Cache {expr = expr, var = var "Synchronized.cache" Undef}; |
77998 | 124 |
|
80073
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
125 |
fun cache_peek (Cache {var, ...}) = peek (value var); |
78008 | 126 |
|
80073
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
127 |
fun cache_eval {persistent} (Cache {expr, var}) = |
77998 | 128 |
change_result var (fn state => |
80073
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
129 |
let |
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
130 |
val result = |
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
131 |
(case peek state of |
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
132 |
SOME result => result |
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
133 |
| NONE => expr ()); |
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
134 |
val state' = |
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
135 |
if persistent then Value result |
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
136 |
else if weak_active state then state |
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
137 |
else Weak_Ref (Unsynchronized.weak_ref result); |
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
138 |
in (result, state') end); |
77998 | 139 |
|
28578 | 140 |
end; |
77998 | 141 |
|
142 |
end; |
|
80073
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
143 |
|
40f5ddeda2b4
further performance tuning (after f906f7f83dae): interactive mode is closer to earlier approach with Lazy.value, which could be relevant with rather complex grammars under tight memory situations;
wenzelm
parents:
78720
diff
changeset
|
144 |
end; |