Go

What is context.AfterFunc and what are the semantics of its stop function?

Question 273HardGo 1.22 to 1.25

func AfterFunc(ctx Context, f func()) (stop func() bool) (Go 1.21) arranges for f to run in its own goroutine once ctx is done. If ctx is already done, f starts right away. For stdlib contexts this avoids keeping a watcher goroutine parked on <-ctx.Done(): registration is just an entry in the parent's children map.

stop() removes the registration:

  • It returns true if this call prevented f from running.
  • It returns false if f has already been started or stop was already called.
  • It does not wait for a running f to finish. If you need that, synchronize yourself.
// Wake a sync.Cond waiter when ctx is canceled
func waitCond(ctx context.Context, mu *sync.Mutex, cond *sync.Cond, ready func() bool) error {
	stop := context.AfterFunc(ctx, func() {
		mu.Lock()
		defer mu.Unlock()
		cond.Broadcast()
	})
	defer stop()

	mu.Lock()
	defer mu.Unlock()
	for !ready() {
		if err := ctx.Err(); err != nil {
			return err
		}
		cond.Wait()
	}
	return nil
}

Typical uses: unblocking APIs that don't accept a context (condition variables, net.Conn deadlines), merging contexts, and cleanup hooks. Calling AfterFunc several times on the same context registers several independent callbacks.

More on Context

All 35 Context questions