Skip to content

Commit 737d232

Browse files
authored
doc multi-threading: fix indentation (#36560)
1 parent a4d0123 commit 737d232

File tree

1 file changed

+40
-40
lines changed

1 file changed

+40
-40
lines changed

doc/src/manual/multi-threading.md

+40-40
Original file line numberDiff line numberDiff line change
@@ -302,47 +302,47 @@ rather pointless as a finalizer). This leads us to a bit of a conundrum.
302302
There are a few approaches to dealing with this problem:
303303

304304
1. When single-threaded, code could call the internal `jl_gc_enable_finalizers`
305-
C function to prevent finalizers from being scheduled
306-
inside a critical region. Internally, this is used inside some functions (such
307-
as our C locks) to prevent recursion when doing certain operations (incremental
308-
package loading, codegen, etc.). The combination of a lock and this flag
309-
can be used to make finalizers safe.
305+
C function to prevent finalizers from being scheduled
306+
inside a critical region. Internally, this is used inside some functions (such
307+
as our C locks) to prevent recursion when doing certain operations (incremental
308+
package loading, codegen, etc.). The combination of a lock and this flag
309+
can be used to make finalizers safe.
310310

311311
2. A second strategy, employed by Base in a couple places, is to explicitly
312-
delay a finalizer until it may be able to acquire its lock non-recursively.
313-
The following example demonstrates how this strategy could be applied to
314-
`Distributed.finalize_ref`:
315-
316-
```
317-
function finalize_ref(r::AbstractRemoteRef)
318-
if r.where > 0 # Check if the finalizer is already run
319-
if islocked(client_refs) || !trylock(client_refs)
320-
# delay finalizer for later if we aren't free to acquire the lock
321-
finalizer(finalize_ref, r)
322-
return nothing
323-
end
324-
try # `lock` should always be followed by `try`
325-
if r.where > 0 # Must check again here
326-
# Do actual cleanup here
327-
r.where = 0
328-
end
329-
finally
330-
unlock(client_refs)
331-
end
332-
end
333-
nothing
334-
end
335-
```
312+
delay a finalizer until it may be able to acquire its lock non-recursively.
313+
The following example demonstrates how this strategy could be applied to
314+
`Distributed.finalize_ref`:
315+
316+
```
317+
function finalize_ref(r::AbstractRemoteRef)
318+
if r.where > 0 # Check if the finalizer is already run
319+
if islocked(client_refs) || !trylock(client_refs)
320+
# delay finalizer for later if we aren't free to acquire the lock
321+
finalizer(finalize_ref, r)
322+
return nothing
323+
end
324+
try # `lock` should always be followed by `try`
325+
if r.where > 0 # Must check again here
326+
# Do actual cleanup here
327+
r.where = 0
328+
end
329+
finally
330+
unlock(client_refs)
331+
end
332+
end
333+
nothing
334+
end
335+
```
336336

337337
3. A related third strategy is to use a yield-free queue. We don't currently
338-
have a lock-free queue implemented in Base, but
339-
`Base.InvasiveLinkedListSynchronized{T}` is suitable. This can frequently be a
340-
good strategy to use for code with event loops. For example, this strategy is
341-
employed by `Gtk.jl` to manage lifetime ref-counting. In this approach, we
342-
don't do any explicit work inside the `finalizer`, and instead add it to a queue
343-
to run at a safer time. In fact, Julia's task scheduler already uses this, so
344-
defining the finalizer as `x -> @spawn do_cleanup(x)` is one example of this
345-
approach. Note however that this doesn't control which thread `do_cleanup`
346-
runs on, so `do_cleanup` would still need to acquire a lock. That
347-
doesn't need to be true if you implement your own queue, as you can explicitly
348-
only drain that queue from your thread.
338+
have a lock-free queue implemented in Base, but
339+
`Base.InvasiveLinkedListSynchronized{T}` is suitable. This can frequently be a
340+
good strategy to use for code with event loops. For example, this strategy is
341+
employed by `Gtk.jl` to manage lifetime ref-counting. In this approach, we
342+
don't do any explicit work inside the `finalizer`, and instead add it to a queue
343+
to run at a safer time. In fact, Julia's task scheduler already uses this, so
344+
defining the finalizer as `x -> @spawn do_cleanup(x)` is one example of this
345+
approach. Note however that this doesn't control which thread `do_cleanup`
346+
runs on, so `do_cleanup` would still need to acquire a lock. That
347+
doesn't need to be true if you implement your own queue, as you can explicitly
348+
only drain that queue from your thread.

0 commit comments

Comments
 (0)