3 回答
TA贡献1829条经验 获得超4个赞
从运行时的角度来看,您会遇到死锁,因为所有例程都尝试发送到通道上,并且没有例程等待接收任何内容。
但为什么会这样呢?我会给你一个故事,因为我喜欢想象当我遇到僵局时我的例程在做什么。
你有两名球员(例程)和一个球(true
价值)。每个球员都在等待一个球,一旦他们拿到球,他们就会将球传回给另一个球员(通过通道)。这就是您的两个例程真正在做的事情,这确实会产生无限循环。
问题是在主循环中引入的第三个玩家。他躲在第二名球员身后,一旦他看到第一名球员空手而归,他就会向他扔另一个球。所以我们最终两个球员都拿着一个球,不能将球传给另一个球员,因为另一个球员已经(第一个)球在他的手中。隐藏的邪恶球员还试图再传一个球。每个人都很困惑,因为有三个球,三个球员,没有空手。
换句话说,您介绍了破坏游戏的第三个玩家。他应该是比赛开始时传递第一个球的仲裁者,看着它,但停止生产球!这意味着,而不是在你的主程序中有一个循环,应该有简单的chan1 <- true
(和一些等待的条件,所以我们不退出程序)。
如果在主程序的循环中启用日志记录,您将看到死锁总是发生在第三次迭代。其他例程的执行次数取决于调度程序。回到故事:第一次迭代是第一个球的开球;下一次迭代是一个神秘的第二个球,但这可以处理。第三次迭代是一个僵局——它使第三个球无法被任何人处理。
TA贡献1841条经验 获得超3个赞
看起来很复杂,但答案很简单。
在以下情况下会死锁:
第一个例程试图写入
chan2
第二条路线是尝试写入
chan1
.Main 正在尝试写入
chan1
.
怎么会这样?例子:
主要写道
chan1
。阻止另一次写入。例程 1:
chan1
从 Main 接收。印刷。写入时阻塞chan2
。例程2:
chan2
接收。印刷。写入时阻塞chan1
。例程 1:
chan1
从例程 2 接收。打印。写入时阻塞chan2
。例程2:
chan2
接收。印刷。写入时阻塞chan1
。主要写道
chan1
。阻止另一次写入。例程 1:
chan1
从 Main 接收。印刷。写入时阻塞chan2
。主要写道
chan1
。阻止另一次写入。
目前所有的例程都被阻止了。IE:
例程 1 无法写入,chan2
因为例程 2 未接收但实际上在尝试写入时被阻止chan1
。但是没有人在听chan1
。
正如@HectorJ 所说,这完全取决于调度程序。但在这种设置中,死锁是不可避免的。
TA贡献1806条经验 获得超5个赞
goroutine 1 [chan send]:
goroutine 5 [chan send]:
goroutine 6 [chan send]:
这说明了一切:你所有的 goroutine 都被阻塞,试图在一个通道上发送,而另一端没有人接收。
所以你的第一个 goroutine 阻塞了 chan2 <- true,你的第二个阻塞了chan1 <- true,你的主 goroutine 阻塞了它自己chan1 <- true。
至于为什么像您说的那样执行两次“完整的 ping-ping”,这取决于调度以及发送方<-chan1决定首先接收的信息。
在我的电脑上,我得到了更多,每次运行它都会有所不同:
chan1
chan2
chan1
chan2
chan1
chan2
chan1
chan2
chan1
chan2
chan1
chan2
chan1
fatal error: all goroutines are asleep - deadlock!
- 3 回答
- 0 关注
- 158 浏览
添加回答
举报