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.

Reply via email to