syoui jyo
syoui jyo

Reputation: 179

golang why can not pass value to channel on the main thread

case1

package main

func main()  {
    dogChan := make(chan int)
    dogChan <- 1
}
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.main()
    /Users/xuzhongwei/Source/awesomeProject/main.go:5 +0x50

case2

package main

func main()  {
    dogChan := make(chan int)

    go func(ch chan int) {
        
    }(dogChan)
    dogChan <- 1
}
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.main()
    /Users/xuzhongwei/Source/awesomeProject/main.go:9 +0x72

case3

package main

func main()  {
    dogChan := make(chan int)

    go func(ch chan int) {
        <- ch
    }(dogChan)
    dogChan <- 1
}

case4

package main

func main()  {
    dogChan := make(chan int)
    
    go func(ch chan int) {
        <- ch
    }(dogChan)
    dogChan <- 1
    dogChan <- 2
}
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.main()
    /Users/xuzhongwei/Source/awesomeProject/main.go:10 +0x90

case5

package main

func main()  {
    dogChan := make(chan int)

    go func(ch chan int) {
        for {
            select {
                case <- ch:
            }
        }

    }(dogChan)
    dogChan <- 1
    dogChan <- 2
    dogChan <- 3
    dogChan <- 4
    dogChan <- 5
}

Could anyone tell me why case1, case2 got errors while case3 is ok? In case1 my guess is that dogChan is not used in goroutine so it is treated to be closed. In case2 my guess is that although dogChan is passed in goroutine but it is not used in goroutine so it is treated to be closed

Could anyone tell me why case4 got errors while case5 is ok?

Upvotes: 3

Views: 1140

Answers (2)

ChuckCottrill
ChuckCottrill

Reputation: 4444

Golang expects program to read message(s) placed into channel.

Consumer (reader) needs to drain (read) all messages from channel, either using simple for-read, or for-select. Channel send and receive both block until sender and receiver are ready.

  • case1, case2 = send one message to channel, block awaiting reader, read zero messages
  • case4 = send one message to channel, block awaiting reader, reader does not consume (read) message
  • case3 = send one message to channel, consume one message from channel, sender blocks awaiting reader
  • case5 = send five messages to channel, consume all (five) messages, each send blocks until reader receives
    // for range over channel
    for msg := range ch {
        // process msg
    }
    
    // for select
    done := false
    for !done {
        select {
            case msg := <-ch: {
                // process msg
            }
            case ch == nil: {
                done = true
            }
        }
    }
    
    // producer should close channel
    close(ch)

Note:

  • channel can be buffered, specify a channel (queue) size
  • channel size default = 1 (unbuffered), writer blocks when channel full

Upvotes: 4

Inian
Inian

Reputation: 85710

Why do you think thats happening in case1 and case2? The channels are meant to behave as a synchronisation primitive between a sender and receiver. You have a sender sending on a channel, dogChan but none is receiving on it. Without a receiving goroutine or a receive operation on a goroutine, the sender simply blocks (being a unbuffered channel)

Same problem on case4, you have two sends on the channel, but a single receive on the goroutine. The dogChan <- 2 will block forever. In case5, if your intention was to read from the channel, simply use a range loop to iterate over the successive values sent over it.

Upvotes: 5

Related Questions