> this is why I avoid mutexes and other concurrency operations that aren't channels; you can't cancel your wait on them
Mutexes are designed to solve different problems -- albeit with overlap. Channels are great if you have a one to one relationship or even a many to one but they're not so good with many to many relationships. That is where you need several routines to have read access and several routines to have write. I'm not saying they can't be used in that way but if you're not careful it's even easier to have goroutines "stuck waiting for something that will never happen" with channels than it is with mutexes. So I'd be very nervous about shoehorning channels into a design they're not well suited for.
Also you can cancel your wait on mutex if there is another goroutine which unlocks that mutex. In fact if you browse the Go source you'd see that channels use mutexes themselves.
Mutexes are designed to solve different problems -- albeit with overlap. Channels are great if you have a one to one relationship or even a many to one but they're not so good with many to many relationships. That is where you need several routines to have read access and several routines to have write. I'm not saying they can't be used in that way but if you're not careful it's even easier to have goroutines "stuck waiting for something that will never happen" with channels than it is with mutexes. So I'd be very nervous about shoehorning channels into a design they're not well suited for.
Also you can cancel your wait on mutex if there is another goroutine which unlocks that mutex. In fact if you browse the Go source you'd see that channels use mutexes themselves.