Can't seem to figure this out: all goroutines are asleep - deadlock!

Hello,

I’m new to Go and have been struggling with the below code; I’ve tried many different things but I can’t seem to get it to run without getting a “fatal error: all goroutines are asleep - deadlock!” error. What am I missing?

package main

import (
	"fmt"
	"sync"
	"time"
)

func main() {
	wg := new(sync.WaitGroup)
	messages := make(chan string)
	for x := 1; x <= 5; x++ {
		wg.Add(1)
		go sayhello(x, wg, &messages)
	}

	for msg := range messages {
		fmt.Println(msg)
	}
	wg.Wait()
	close(messages)
}

func sayhello(count int, wg *sync.WaitGroup, messages *chan string) {
	defer wg.Done()
	time.Sleep(time.Millisecond * time.Duration(1000))
	*messages <- fmt.Sprintf("hello: %d", count)
}

The output of the above is:

hello: 1
hello: 5
hello: 4
hello: 3
hello: 2
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
main.main()
	/tmp/sandbox833114511/main.go:17 +0x1a0

Here is a modified version that worked for me. Comment out the line with close(messages) and it will deadlock. Using for range on a channel is the cause of the deadlock as it’ll never exit that loop.

package main

import (
	"fmt"
	"sync"
	"time"
	"log"
)

func main() {
	wg := new(sync.WaitGroup)
	messages := make(chan string)
	for x := 1; x <= 5; x++ {
		wg.Add(1)
		go sayhello(x, wg, &messages)
	}

	go func(wg *sync.WaitGroup, messages chan string) {
		log.Println("waiting")
		wg.Wait()
		log.Println("done waiting")
		close(messages)
	}(wg, messages)

	for msg := range messages {
		fmt.Println(msg)
	}
}

func sayhello(count int, wg *sync.WaitGroup, messages *chan string) {
	defer wg.Done()
	time.Sleep(time.Millisecond * time.Duration(1000 * count))
	*messages <- fmt.Sprintf("hello: %d", count)
	log.Println("sent message ", count)
}

To explain the background of the problem: The range operator reads from the channel until the channel is closed. So in the original code, the for-range loop keeps waiting for more input from the channel, and wg.Wait() is never reached. Suneil’s solution separates reading the channel from waiting for the workers to finish.

2 Likes

Just

package main

import (
	"fmt"
	"sync"
	"time"
)

func main() {
	wg := new(sync.WaitGroup)
	messages := make(chan string, 5)
	for x := 1; x <= 5; x++ {
		wg.Add(1)
		go sayhello(x, wg, &messages)
	}
	wg.Wait()
	close(messages)
	for msg := range messages {
		fmt.Println(msg)
	}
}

func sayhello(count int, wg *sync.WaitGroup, messages *chan string) {
	defer wg.Done()
	time.Sleep(time.Millisecond * time.Duration(1000))
	*messages <- fmt.Sprintf("hello: %d", count)
}

Only one difference :slight_smile:
You can want to consider mutex before use sleep in goroutines also

And one more

package main

import (
	"fmt"
	"strconv"
	"sync"
)

var wg sync.WaitGroup

func main() {
	message := make(chan string)
	go sayhello(message)
	for x := int64(1); x <= 5; x++ {
		m := "hello : " + strconv.FormatInt(x, 10)
		message <- m
	}
	wg.Wait()
}
func DisplayMsg(m string) {
	defer wg.Done()
	fmt.Printf("hello: %s\n", m)
	return
}
func sayhello(message chan string) {
	for {
		m, more := <-message
		wg.Add(1)
		go DisplayMsg(m)
		if more == false {
			close(message)
			return
		}
	}
}

You have to close the channel to notify the for loops to finish.

https://play.golang.org/p/nU2Rq6PJdO

And don’t have to pass a pointer to the channel, the channel is already a pointer.

Thank you all; I understand now.

-Robert

Wouldn’t putting a mutex around a call to time.Sleep make the go routines appear to run serially? For example if 5 goroutines each mutex around a time.Sleep call of 1 second, then the first routine would wait 1 second, the second routine 2 seconds (waits for first routine to finish before it even starts sleeping)… and the fifth routine 5 seconds, rather than all five waiting for 1 second at the same time?

Thanks,

-Robert

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.