6
6
AbstractLock
7
7
8
8
Abstract supertype describing types that
9
- implement the thread-safe synchronization primitives:
9
+ implement the synchronization primitives:
10
10
[`lock`](@ref), [`trylock`](@ref), [`unlock`](@ref), and [`islocked`](@ref).
11
11
"""
12
12
abstract type AbstractLock end
@@ -24,30 +24,33 @@ assert_havelock(l::AbstractLock, tid::Task) =
24
24
assert_havelock (l:: AbstractLock , tid:: Nothing ) = error (" concurrency violation detected" )
25
25
26
26
"""
27
- NotALock
27
+ AlwaysLockedST
28
28
29
- A struct that pretends to be always locked on the original thread it was allocated on,
29
+ This struct does not implement a real lock, but instead
30
+ pretends to be always locked on the original thread it was allocated on,
30
31
and simply ignores all other interactions.
32
+ It also does not synchronize tasks; for that use a [`CooperativeLock`](@ref) or a
33
+ real lock such as [`RecursiveLock`](@ref).
31
34
This can be used in the place of a real lock to, instead, simply and cheaply assert
32
35
that the operation is only occurring on a single thread.
33
- And is thus functionally equivalent to allocating a real, recursive lock,
36
+ And is thus functionally equivalent to allocating a real, recursive, task-unaware lock
34
37
immediately calling `lock` on it, and then never calling a matching `unlock`,
35
38
except that calling `lock` from another thread will throw a concurrency violation exception.
36
39
"""
37
- struct NotALock <: AbstractLock
40
+ struct AlwaysLockedST <: AbstractLock
38
41
ownertid:: Int16
39
- NotALock () = new (Threads. threadid ())
42
+ AlwaysLockedST () = new (Threads. threadid ())
40
43
end
41
- assert_havelock (l:: NotALock ) = assert_havelock (l, l. ownertid)
42
- lock (l:: NotALock ) = assert_havelock (l)
43
- unlock (l:: NotALock ) = assert_havelock (l)
44
- trylock (l:: NotALock ) = l. ownertid == Threads. threadid ()
45
- islocked (:: NotALock ) = true
44
+ assert_havelock (l:: AlwaysLockedST ) = assert_havelock (l, l. ownertid)
45
+ lock (l:: AlwaysLockedST ) = assert_havelock (l)
46
+ unlock (l:: AlwaysLockedST ) = assert_havelock (l)
47
+ trylock (l:: AlwaysLockedST ) = l. ownertid == Threads. threadid ()
48
+ islocked (:: AlwaysLockedST ) = true
46
49
47
50
"""
48
51
CooperativeLock
49
52
50
- An optimistic lock, which can be used cheaply to check for missing
53
+ An optimistic lock for cooperative tasks , which can be used cheaply to check for missing
51
54
lock/unlock guards around `wait`, in the trivial (conflict-free, yield-free, single-threaded, non-recursive) case,
52
55
without paying the cost for a full RecursiveLock.
53
56
"""
@@ -56,9 +59,24 @@ mutable struct CooperativeLock <: AbstractLock
56
59
CooperativeLock () = new (nothing )
57
60
end
58
61
assert_havelock (l:: CooperativeLock ) = assert_havelock (l, l. owner)
59
- lock (l:: CooperativeLock ) = (l. owner === nothing || error (" concurrency violation detected" ); l. owner = current_task (); nothing )
60
- unlock (l:: CooperativeLock ) = (assert_havelock (l); l. owner = nothing ; nothing )
61
- trylock (l:: CooperativeLock ) = (l. owner === nothing ? (l. owner = current_task (); true ) : false )
62
+ function lock (l:: CooperativeLock )
63
+ l. owner === nothing || error (" concurrency violation detected" )
64
+ l. owner = current_task ()
65
+ nothing
66
+ end
67
+ function unlock (l:: CooperativeLock )
68
+ assert_havelock (l)
69
+ l. owner = nothing
70
+ nothing
71
+ end
72
+ function trylock (l:: CooperativeLock )
73
+ if l. owner === nothing
74
+ l. owner = current_task ()
75
+ return true
76
+ else
77
+ return false
78
+ end
79
+ end
62
80
islocked (l:: CooperativeLock ) = l. owner != = nothing
63
81
64
82
@@ -142,15 +160,15 @@ function notify(c::GenericCondition, @nospecialize(arg), all, error)
142
160
if all
143
161
cnt = length (c. waitq)
144
162
for t in c. waitq
145
- error ? schedule (t, arg, error= error) : schedule (t, arg )
163
+ schedule (t, arg, error= error)
146
164
end
147
165
empty! (c. waitq)
148
166
elseif ! isempty (c. waitq)
149
167
cnt = 1
150
168
t = popfirst! (c. waitq)
151
- error ? schedule (t, arg, error= error) : schedule (t, arg )
169
+ schedule (t, arg, error= error)
152
170
end
153
- cnt
171
+ return cnt
154
172
end
155
173
156
174
notify_error (c:: GenericCondition , err) = notify (c, err, true , true )
@@ -173,8 +191,6 @@ Create a level-triggered event source. Tasks that call [`wait`](@ref) on an
173
191
After `notify` is called, the `Event` remains in a signaled state and
174
192
tasks will no longer block when waiting for it.
175
193
176
- This object is NOT thread-safe. See [`Threads.EventMT`](@ref) for a thread-safe version.
177
-
178
194
!!! compat "Julia 1.1"
179
195
This functionality requires at least Julia 1.1.
180
196
"""
@@ -215,8 +231,7 @@ const ConditionST = GenericCondition{CooperativeLock}
215
231
const EventST = GenericEvent{CooperativeLock}
216
232
217
233
# default (Julia v1.0) is currently single-threaded
218
- const Condition = GenericCondition{NotALock}
219
- const Event = EventST
234
+ const Condition = GenericCondition{AlwaysLockedST}
220
235
221
236
222
237
# # scheduler and work queue
0 commit comments