为什么这里可能发生死锁?

huangapple go评论85阅读模式
英文:

Why is deadlock posssible here?

问题

我正在学习关于Go语言中死锁及其出现的情况。我正在查看这段代码。我知道这里可能会出现死锁,但我找不到具体原因。有人可以解释一下吗?

package main

import "fmt"

func reuters(ch chan string) {
    ch <- "REUTERS"
}
func bloomberg(ch chan string) {
    ch <- "BLOOMBERG"
}
func newsReader(reutersCh chan string, bloombergCh chan string) {
    ch := make(chan string, 5)
    go func() {
        ch <- (<-reutersCh)
    }()
    go func() {
        ch <- (<-bloombergCh)
    }()
    x := <-ch
    fmt.Printf("got news from %s \n", x)
}
func main() {
    reutersCh := make(chan string)
    bloombergCh := make(chan string)
    go reuters(reutersCh)
    go bloomberg(bloombergCh)
    newsReader(reutersCh, bloombergCh)
    newsReader(reutersCh, bloombergCh)
}

这段代码中可能会出现死锁的原因是:在newsReader函数中,有两个goroutine分别从reutersChbloombergCh通道中接收数据,并将数据发送到ch通道中。然后,在主函数中,我们调用了两次newsReader函数,每次都使用相同的reutersChbloombergCh通道。由于ch通道的缓冲区大小为5,而我们只从中接收了一个数据,所以第二次调用newsReader函数时,将会发生死锁。因为第二次调用时,ch通道已经被第一次调用中的goroutine占满,无法再接收新的数据。

为了解决这个问题,你可以将ch通道的缓冲区大小增加到足够大,以容纳所有的数据,或者在每次调用newsReader函数时,使用新的通道来避免死锁。

英文:

I am currently learning about deadlocks in Go and when they can appear. I am viewing this code. I know a deadlock is possible here, but I cannot find it. Can someone please explain it to me?

package main

import &quot;fmt&quot;

func reuters(ch chan string) {
	ch &lt;- &quot;REUTERS&quot;
}
func bloomberg(ch chan string) {
	ch &lt;- &quot;BLOOMBERG&quot;
}
func newsReader(reutersCh chan string, bloombergCh chan string) {
	ch := make(chan string, 5)
	go func() {
		ch &lt;- (&lt;-reutersCh)
	}()
	go func() {
		ch &lt;- (&lt;-bloombergCh)
	}()
	x := &lt;-ch
	fmt.Printf(&quot;got news from %s \n&quot;, x)
}
func main() {
	reutersCh := make(chan string)
	bloombergCh := make(chan string)
	go reuters(reutersCh)
	go bloomberg(bloombergCh)
	newsReader(reutersCh, bloombergCh)
	newsReader(reutersCh, bloombergCh)
}

答案1

得分: 2

当你想从一个空通道中读取时,该通道会阻塞。在运行以下代码之后:

go reuters(reutersCh)
go bloomberg(bloombergCh)

reutersCh 通道中会有一个项目,bloombergCh 通道中也会有一个项目。当你运行

newsReader(reutersCh, bloombergCh)

你启动了两个从两个通道中读取的例程。很有可能,在第二次运行

newsReader(reutersCh, bloombergCh)

之前,这两个例程就已经完成了。在这种情况下,reutersChbloombergCh 是空的,所以你无法从它们中读取。当你无法从这些通道中读取时,你也无法向 newsReader 函数中的本地通道 ch 写入。当你无法向通道 ch 写入时,你也无法从通道中读取,因此它会阻塞。

总之,你在 reutersChbloombergCh 中写入一次,并尝试从它们中读取两次。两个例程肯定会阻塞,当第二次调用 newsReader 的两个例程阻塞时(这是非常可能的),你的程序将完全阻塞。

英文:

When you want to read from an empty channel, the channel blocks. After running:

go reuters(reutersCh)
go bloomberg(bloombergCh)

there will be one item in reutersCh and one item in bloombergCh. When you run

newsReader(reutersCh, bloombergCh)

you start two routines that read from both channels. It is very likely, that they finish before

newsReader(reutersCh, bloombergCh)

runs a second time. In this case, reutersCh and bloombergCh are empty, so der is no way you can read from them. When you can't read from these channels, you also can't write to the local channel ch in the newsReader function. When you can't write to the channel ch you can't read from the channel and therefore it blocks.

In conclusion, you write in reutersCh and bloombergCh once and try to read from them twice. Two routines will block for sure and when the two routines from the second call of newsReader block (which is very likely), your program will block completely.

huangapple
  • 本文由 发表于 2022年1月30日 20:46:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/70914752.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定