proposal: sync: remove the Cond type (original) (raw)
In the discussion on #16620, I've noticed that the majority of use-cases folks describe for sync.Cond turn out to work fine with a channel instead: (*sync.Cond).Broadcast corresponds to calling close on the channel, and (*sync.Cond).Signal corresponds to sending on the channel.
The existence of sync.Cond suggests that people might want to use it, but it is currently under-documented (#20491), incompatible with other Go synchronization patterns (e.g. select statements; see #16620), and unlike most other types in the sync package, does not have a valid zero-value (its Wait method requires a non-nil L field). It has an additional "no copy" invariant enforced through both a run-time dynamic check and special-case code in the vet tool.
On top of that, condition variables are fiendishly difficult to use: they are prone to either missed or spurious signals [citation needed — experience reports welcome].
An audit of the Go standard library shows only a handful of uses:
io/pipe.go: The use ofsync.Condwas added in https://golang.org/cl/4252057. The previous implementation used channels and had no known bugs.syscall/net_nacl.go: The comment there says "We do not use channels because we need to be able to handle writes after and during close, and because a chan byte would require too many send and receive operations in real use." It does not explain why these considerations preclude the use of channels (e.g. a separate 'chan struct{}' to signal closing, and channels of tokens or slices rather than channels of tokens or bytes).net/http/h2_bundle.go: There are twosync.Conds in this file. One is is in a struct "likeio.Pipe". The other is only used withBroadcast(neverSignal), and can thus be replaced with a channel that is closed to broadcast readiness.net/http/server.go: Thissync.Condis again only used withBroadcast, and thus easy to replace with a channel.crypto/tls/conn.go: Again only used withBroadcast.
Of the above uses, only the one in syscall/net_nacl.go does not have an obvious channel equivalent. However, it appears to be used to limit the size of a buffer, and I know of at least one similar "limiter" API (x/sync/semaphore) that is implemented in terms of channels in order to support interoperation with the standard context package. (I did the Cond-to-channel conversion myself on a prototype of that package before it was open-sourced.)
In light of the above observations, I propose that we remove the Cond type from the sync package in Go 2.