Why does this code deadlock?

I’m trying to isolate a deadlock problem in a bigger program and have reproduced my issue in the sample below (run it yourself here: https://play.golang.org/p/dHtc78LDDD)

package main

import "log"

type NotifyOp struct {
	/** Channel to respond on once op completed */
    response chan bool
}

type Hub struct {
	doSomething chan *NotifyOp
}

func (h *Hub) run() {
	
	log.Printf("Hub: Waiting for DoSomething")
	notifyOp := <-h.doSomething
	log.Printf("Hub: Doing Something")
	notifyOp.response <- true
	log.Printf("Hub: Done Something")
	
	log.Printf("Hub: Finished")
}

type Client struct {
	hub * Hub
	
	finished chan bool
}

func (c *Client) run() {
	
	op := NotifyOp{ 
		response: make(chan bool) ,
	}
	
	log.Printf("Client: Calling Hub")
	c.hub.doSomething <- &op
	log.Printf("Client: Waiting on Finish")
	<- op.response
	log.Printf("Client: Done calling Hub")
	
	c.finished <- true
	
	log.Printf("Client: Finished")
}

func main() {
		
	finishedChannel := make(chan bool)
	hub := Hub{}
	client := Client{ 
		hub: &hub,
		finished: finishedChannel,
	}
	
	go hub.run()
	go client.run()
	
	log.Printf("Main: Waiting on Finish")
	<- finishedChannel
	log.Printf("Main: Finished")
}

This outputs:

2009/11/10 23:00:00 Main: Waiting on Finish
2009/11/10 23:00:00 Client: Calling Hub
2009/11/10 23:00:00 Hub: Waiting for DoSomething
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
main.main()
	/tmp/sandbox304437714/main.go:61 +0x160

goroutine 5 [chan receive (nil chan)]:
main.(*Hub).run(0x1040c108, 0x0)
	/tmp/sandbox304437714/main.go:17 +0x80
created by main.main
	/tmp/sandbox304437714/main.go:57 +0x100

goroutine 6 [chan send (nil chan)]:
main.(*Client).run(0x1040c110, 0x0)
	/tmp/sandbox304437714/main.go:38 +0xe0
created by main.main
	/tmp/sandbox304437714/main.go:58 +0x120

My question is why does this occur? I have some ideas, but I’m hoping that this will be obvious to more experienced go developers. Any pointers appreciated.

Literally a minute after posting I realised the problem - the doSomething channel was not initialised :frowning:

hub := Hub{
    doSomething: make(chan *NotifyOp),
}

This solves the problem.

1 Like

Yup, that’s it. The runtime even says so

goroutine 6 [chan send (nil chan)]:

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