That is ok, though, because the goroutine is exiting anyway. But I take your point, it's still a race condition -- two atomic operations in a row aren't helping. It's the same situation as testing (but not acquiring) a mutex before entering a function.
On Friday, August 18, 2017 at 9:59:51 PM UTC-4, Carl Mastrangelo wrote: > > FYI: It is possible for `done` to never be sent to. For example > consider the following sequence: > > goroutine: ch <- 1 > main: <- 1 > main: run defer > main: fin = atomic load > goroutine: atomic store > main: not 1, return > > > On Friday, August 18, 2017 at 11:13:36 AM UTC-7, bill....@talentinc.com > wrote: >> >> Hi, >> >> https://play.golang.org/p/lR6_mxSjtb >> >> I have two long running things to do, I'd like to do them in parallel, >> then sync up at the end. I've written it as a function which gets one thing >> done, and which backgrounds the second thing with a goroutine. Thing one >> has a lot of reasons to exit early, and I need to signal those to thing two >> so that the go routine can exit cleanly and not create a goroutine leak. >> Standard fare, usually solved by introducing a channel and a select >> statement. I want to signal done for early exits, including panics, so I >> thought I would write to the done channel in a defer block. That caused a >> problem, because in the happy case, both the foreground and the background >> routines are finished, the done channel has no reader, so writing to it in >> the defer block causes "fatal error: all goroutines are asleep - deadlock!" >> So I introduced a new boolean variable ("clean_finish") that is false until >> the background job completes, and which is tested in the defer block before >> writing to the done channel. Is there anything wrong with my approach? You >> can see the code in the playground link above, or down below. >> >> >> package main >> >> import ( >> "sync/atomic" >> "fmt" >> "time" >> ) >> >> func main() { >> ch := make(chan int) >> done := make(chan struct{}) >> var clean_finish uint32 >> defer func() { >> fin := atomic.LoadUint32(&clean_finish) >> if fin != 1 { >> done <- struct{}{} >> } >> }() >> go func() { >> defer func() { >> fmt.Println("we're done here") >> }() >> select { >> case <-time.After(time.Second * 1): >> ch <- 1 >> atomic.StoreUint32(&clean_finish, 1) >> case <- done: >> fmt.Println("early exit") >> } >> }() >> panic("bye") // comment this out to see normal behavior >> n := <- ch >> fmt.Printf("n: %v\n", n) >> } >> >> -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.