Go run -race main.go hasn't returned yet

If I run this code, with “go -race main.go” it never returns. When I run go run main.go, sometimes I get

"fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
main.main()
/home/peter/go/src/github.com/stackskill0/concur/channels/n21/main.go:37 +0x1da

goroutine 6 [chan receive]:
main.main.func2(0xc42001e0c0, 0xc4200120f0)
/home/peter/go/src/github.com/stackskill0/concur/channels/n21/main.go:27 +0x7c
created by main.main
/home/peter/go/src/github.com/stackskill0/concur/channels/n21/main.go:22 +0xd6

goroutine 7 [semacquire]:
sync.runtime_Semacquire(0xc4200120fc)
/usr/local/go/src/runtime/sema.go:56 +0x39
sync.(*WaitGroup).Wait(0xc4200120f0)
/usr/local/go/src/sync/waitgroup.go:131 +0x72
main.main.func3(0xc4200120f0, 0xc42001e0c0)
/home/peter/go/src/github.com/stackskill0/concur/channels/n21/main.go:33 +0x2b
created by main.main
/home/peter/go/src/github.com/stackskill0/concur/channels/n21/main.go:32 +0x102
exit status 2"

I’m getting a deadlock and don’t understand why. Thanks for looking!


import (
	"fmt"
	"sync"
)

func main() {

	myCh := make(chan string)

	var wq sync.WaitGroup

	wq.Add(2)
	go func() {
		for i := 0; i < 10; i++ {
			myCh <- "anom 1"
		}
		wq.Done()
	}()

	go func() {
		for i := 0; i < 10; i++ {
			myCh <- "anom 2"
		}

		fmt.Println(<-myCh)
		fmt.Println("Clear!")
		wq.Done()
	}()

	go func() {
		wq.Wait()
		close(myCh)
	}()

	for ch := range myCh {
		fmt.Println("ch:", ch)
	}

}

You have a logic race between the

fmt.Println(<-myCh)
fmt.Println("Clear!")
wq.Done()

in one of your goroutines and the

for ch := range myCh {
	fmt.Println("ch:", ch)
}

in the main routine. If the last loop manages to read all the channel values the first <-myCh will block, the waitgroup will never get done, the channel will never close and the program doesn’t terminate, potentially crashing with the deadlock output.

1 Like

Use defer wq.Done( ) inside of your go routine and put your wq.Wait() outside your go routine in the bottom.

Thanks for you help. I’m not sure learning more about the waitgroup code. It seems most people don’ use it. Anyway, I feel I kind of cheated, but I don’t get a race condition anymore.
This is what I ended up with:

package main

import (
	"fmt"
	"sync"
)

var wq sync.WaitGroup

func main() {

	myCh := make(chan string)

	wq.Add(2)
	go func() {
		defer wq.Done()
		for i := 0; i < 10; i++ {
			myCh <- "anom 1"
		}
	}()

	go func() {
		defer wq.Done()
		for i := 0; i < 10; i++ {
			myCh <- "anom 2"
		}

		/* 		fmt.Println(<-myCh)
		   		fmt.Println("Clear!") */

	}()

	go func() {
		wq.Wait()
		close(myCh)
		fmt.Println("Closed myCH")

	}()

	for ch := range myCh {
		fmt.Println("ch:", ch)
	}

}

Yep, that looks fine. I don’t think you should feel cheated, nor avoid waitgroups. They are quite common, at least I use them all the time.

2 Likes

Thanks!