@@ -321,11 +321,23 @@ func runfinq() {
321
321
// closing p.d, causing syscall.Write to fail because it is writing to
322
322
// a closed file descriptor (or, worse, to an entirely different
323
323
// file descriptor opened by a different goroutine). To avoid this problem,
324
- // call runtime. KeepAlive(p) after the call to syscall.Write.
324
+ // call KeepAlive(p) after the call to syscall.Write.
325
325
//
326
326
// A single goroutine runs all finalizers for a program, sequentially.
327
327
// If a finalizer must run for a long time, it should do so by starting
328
328
// a new goroutine.
329
+ //
330
+ // In the terminology of the Go memory model, a call
331
+ // SetFinalizer(x, f) “synchronizes before” the finalization call f(x).
332
+ // However, there is no guarantee that KeepAlive(x) or any other use of x
333
+ // “synchronizes before” f(x), so in general a finalizer should use a mutex
334
+ // or other synchronization mechanism if it needs to access mutable state in x.
335
+ // For example, consider a finalizer that inspects a mutable field in x
336
+ // that is modified from time to time in the main program before x
337
+ // becomes unreachable and the finalizer is invoked.
338
+ // The modifications in the main program and the inspection in the finalizer
339
+ // need to use appropriate synchronization, such as mutexes or atomic updates,
340
+ // to avoid read-write races.
329
341
func SetFinalizer (obj any , finalizer any ) {
330
342
if debug .sbrk != 0 {
331
343
// debug.sbrk never frees memory, so no finalizers run
0 commit comments