理解 Go 中的死锁

Understanding a Deadlock in Go

我从编程课程中给出的示例中摘录了以下内容,但我不确定为什么会发生死锁。

package main

import (
    "fmt"
)

var (
    Count      int = 0
    nFunctions int = 2
)

var sema = make(chan int)

func increment(ch chan int, nSteps int) {
    for i := 0; i < nSteps; i++ {
        <- sema  
        cnt := Count
        Count = cnt + 1
        ch <- 1
        sema <- 1
    }
    return
}

func main() {
    ch := make(chan int)
    sema <- 1
    go increment(ch, 1000)
    go increment(ch, 1000)

    for i := 0; i < nFunctions*1000; i++ {
        <-ch
    }

    fmt.Printf("Count = %d\n", Count)
}

奇怪的是,当我主要将语句从 sema <- 1 更改为

时,并没有发生死锁
go func () {
sema <- 1
}()

非常感谢对此的任何解释。错误信息是: 致命错误:所有 goroutines 都睡着了 - 死锁!

goroutine 1 [chan 发送]: main.main()

频道同时阻止发送者和接收者。如果你发送一些东西,你会被阻止,直到它被接收。您可以进一步减少代码,您只需要一个通道,然后写入该通道。请注意,您还可以使用 buffered channel,它允许在不阻塞的情况下写入缓冲区长度。但是,如果缓冲区已满,它仍然会阻塞。