You might want to consider using a sync.WaitGroup.  It’s for such situations.

 

John

    John Souvestre - New Orleans LA

 

From: golang-nuts@googlegroups.com [mailto:golang-nuts@googlegroups.com] On 
Behalf Of bill.war...@talentinc.com
Sent: 2017 August 18, Fri 13:01
To: golang-nuts
Subject: [go-nuts] Is this bad concurrency?

 

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.

-- 
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