package main
import (
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup
func main() {
ch := make(chan int) // Declare the channel inside main()
wg.Add(4)
go sender(ch, 42)
go receiver(ch)
go sender(ch, 7)
go receiver(ch)
wg.Wait()
}
func receiver(ch <-chan int) {
time.Sleep(5 * time.Second)
i := <-ch
fmt.Printf("RECEIVING %v \n", i)
wg.Done()
}
func sender(ch chan<- int, i int) {
ch <- i
wg.Done()
}
到目前为止,我对 go 中无缓冲通道的了解是
如果通道没有缓冲,发送方将阻塞,直到接收方从通道读取数据。如果发送者在接收者读取第一条消息之前尝试发送另一条消息,它将被无限期地阻塞,从而导致死锁。
这不是真的吗?
现在,我希望这段代码会出现死锁,如
启动了两个发送者协程(sender(ch, 42) 和 sender(ch, 7))。 启动了两个接收器 goroutine (receiver(ch))。 每个发送者 goroutine 在 unbuffered 通道 ch 上发送一个值。 每个接收器 goroutine 在尝试从通道读取数据之前都会等待 5 秒。
发送者 goroutine 立即发送它们的值,但接收者 goroutine 在尝试从通道读取之前会等待 5 秒。由于通道是无缓冲的,这会导致发送者 goroutine 无限期地阻塞,从而导致死锁。
任何人都可以解释一下,为什么上面的代码不会造成死锁?
Chat-gpt 帮不上忙!无法得到满意的解释。
只是添加,我可以使用
创建死锁wg.Add(3)
go sender(ch, 42)
go receiver(ch)
go sender(ch, 7)
提前致谢。
如果通道没有缓冲,发送方将阻塞,直到接收方从通道读取数据。
正确。严格来说,发送方将阻塞,直到接收方“准备好”读取,因为在无缓冲通道的情况下,读取直接从发送方 goroutine 进行到接收方 goroutine。 (请参阅语言规范。)
如果发送者在接收者读取第一条消息之前尝试发送另一条消息,它将被无限期地阻塞,从而导致死锁。第二个发送者确实会被阻塞,但不会无限期地被阻塞,并且不会发生死锁,因为不满足死锁的条件——等待同一共享资源的不同 goroutine 之间不存在相互依赖。一旦接收者醒来并从通道接收数据,至少有一个发送者 goroutine 能够继续进行。
发送者 goroutine 立即发送它们的值,但接收者 goroutine 在尝试从通道读取之前会等待 5 秒。由于通道是无缓冲的,这会导致发送者 goroutine 无限期地阻塞,从而导致死锁。
发送者实际上不会立即发送他们的值,因为通道是无缓冲的。它们必须等待接收器从通道读取数据,此时值将通过通道传送。这是一个微妙的区别,但它可能有助于澄清您的理解。
如上所述,死锁的条件不满足,因为 goroutine 之间不存在循环依赖。确实,睡眠 Goroutine 此时不可运行,但当计时器返回时它将变得可运行。当存在挂起的计时器时,Go 的死锁检测器将退出,如您在
源