简体   繁体   中英

Why does sending a value more than buffered channel size in Golang causes deadlock error?

// By default channels are _unbuffered_, meaning that they
// will only accept sends (`chan <-`) if there is a
// corresponding receive (`<- chan`) ready to receive the
// sent value. _Buffered channels_ accept a limited
// number of  values without a corresponding receiver for
// those values.

package main

import "fmt"

func main() {

    // Here we `make` a channel of strings buffering up to
    // 2 values.
    messages := make(chan string, 2)

    // Because this channel is buffered, we can send these
    // values into the channel without a corresponding
    // concurrent receive.
    messages <- "buffered"
    messages <- "channel"
    messages <- "channel1" //I added this. 

    // Later we can receive these two values as usual.
    fmt.Println(<-messages)
    fmt.Println(<-messages)
}

Error it throws:

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.main()
    /tmp/sandbox795158698/prog.go:23 +0x8d

Questions:

  1. Can't we send more values than buffer size?
  2. Why the error says "all goroutines are asleep - deadlock?" when there are no goroutines here in the code?
  3. Why is it this a deadlock? Please explain?

PlayGroundLink

An attempt to write to a full channel will block until some other goroutine reads from it. In your program, there are no other goroutines. So when you write to the full channel, the main goroutine blocks, and since there are no other goroutines, there is no chance that the main goroutine ever can progress. That is a deadlock.

Adding to the above answer: https://stackoverflow.com/a/61512364/4106031

package main

import (
    "fmt"
    "github.com/practo/klog/v2"
    "os"
    "os/signal"
    "syscall"
    "time"
)

func producer(msgBuf chan<- string) {
    for i := 0; ; i++ {
        fmt.Printf("sent: %d\n", i)
        msgBuf <- fmt.Sprintf("%d", i)
        time.Sleep(1 * time.Second)
    }
}

func process(msgBuf <-chan string) {
    time.Sleep(10 * time.Second)
    for {
        select {
        case msg := <-msgBuf:
            fmt.Printf("processing: %v\n", msg)
            time.Sleep(10 * time.Second)
            fmt.Printf("processed: %v\n", msg)
        }
    }
}

func main() {
    msgBuf := make(chan string, 2)
    go producer(msgBuf)
    go process(msgBuf)

    sigterm := make(chan os.Signal, 1)
    signal.Notify(sigterm, syscall.SIGINT, syscall.SIGTERM)
    for {
        select {
        default:
        case <-sigterm:
            klog.Info("SIGTERM signal received")
            os.Exit(1)
        }
    }
}

This won't cause the deadlock as you are running them in different go routines.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM