英文:
goroutine to print odd and even number alternatively is running into deadlock
问题
我目前正在学习golang。我想检查一下golang的通道是如何工作的。我创建了一个程序,其中两个goroutine会交替打印奇数和偶数。尽管程序打印得很正确,但在最后却显示了一个死锁错误。从错误消息中无法清楚地看出是什么导致了这个问题。
谢谢大家的回复。我编写了以下代码来解决这个问题。
func main() {
even := make(chan bool)
odd := make(chan bool)
done := make(chan bool)
//var wait sync.WaitGroup
//wait.Add(2)
go func() {
for i := 0; i <= 10; i += 2 {
<-even
print("Even ====>")
println(i)
odd <- true
}
close(odd)
close(even)
done <- true
// wait.Done()
}()
go func() {
for i := 1; ; i += 2 {
_, ok := <-odd
if !ok {
//wait.Done()
return
}
print("Odd ====>")
println(i)
select {
case even <- true:
case <-done:
return
}
}
}()
even <- true
//wait.Wait()
<-done
}
英文:
I am currently learning golang. I wanted to check how golang channels work. I have created a program where two goroutines will print odd and even numbers alternatively. Even though the program is printing correctly, it is showing a deadlock error at the end. It is not clear from error message what is causing this issue.
func main() {
even := make(chan bool)
odd := make(chan bool)
go func() {
defer close(odd)
for i := 0; i <= 10; i += 2 {
<-even
print("Even ====>")
println(i)
odd <- true
}
}()
var wait sync.WaitGroup
wait.Add(1)
go func() {
for i := 1; i <= 10; i += 2 {
_, ok := <-odd
if !ok {
wait.Done()
return
}
print("Odd ====>")
println(i)
even <- true
}
}()
even <- true
wait.Wait()
}
[Edit]
Thanks everyone for your reply. I wrote the following code to solve the problem.
func main() {
even := make(chan bool)
odd := make(chan bool)
done := make(chan bool)
//var wait sync.WaitGroup
//wait.Add(2)
go func() {
for i := 0; i <= 10; i += 2 {
<-even
print("Even ====>")
println(i)
odd <- true
}
close(odd)
close(even)
done <- true
// wait.Done()
}()
go func() {
for i := 1; ; i += 2 {
_, ok := <-odd
if !ok {
//wait.Done()
return
}
print("Odd ====>")
println(i)
select {
case even <- true:
case <-done:
return
}
}
}()
even <- true
//wait.Wait()
<-done
}
</details>
# 答案1
**得分**: 2
以下是未来读者的代码:
```go
package main
import "sync"
func main() {
even := make(chan bool)
odd := make(chan bool)
go func() {
defer close(odd)
for i := 0; i <= 10; i += 2 {
<-even
print("Even ====>")
println(i)
odd <- true
}
}()
var wait sync.WaitGroup
wait.Add(1)
go func() {
for i := 1; i <= 10; i += 2 {
_, ok := <-odd
if !ok {
wait.Done()
return
}
print("Odd ====>")
println(i)
even <- true
}
}()
even <- true
wait.Wait()
}
死锁很可能很容易发现,它发生在这里 odd <- true
,因为向一个无缓冲(或已满)的通道写入数据。在第二个 goroutine 的最后一次迭代中,使用了这个循环 for i := 1; i <= 10; i += 2 {
,通道 odd
已经被第一个 goroutine 写入,但第二个 goroutine 无法读取它,因为迭代条件不再匹配,因为在特定的迭代中 i + 2 = 11
,而 11 > 10
,导致迭代停止并且通道保持填充状态。
现在,另一个 goroutine 尝试向 odd
通道写入数据,结果被阻塞,并且永远被阻塞,但由于运行时可以轻松检测到这一点...之后很快就会产生死锁。
英文:
Just in case you don't end up linking your code, here it is for future readers
package main
import "sync"
func main() {
even := make(chan bool)
odd := make(chan bool)
go func() {
defer close(odd)
for i := 0; i <= 10; i += 2 {
<-even
print("Even ====>")
println(i)
odd <- true
}
}()
var wait sync.WaitGroup
wait.Add(1)
go func() {
for i := 1; i <= 10; i += 2 {
_, ok := <-odd
if !ok {
wait.Done()
return
}
print("Odd ====>")
println(i)
even <- true
}
}()
even <- true
wait.Wait()
}
The deadlock is likely quite easy to figure that it occurs here odd <- true
as a result of a write into an unbuffered (or filled up) channel.
On the last iteration of your second goroutine having this loop for i := 1; i <= 10; i += 2 {
, the channel odd
has been written into already by the first goroutine but the second goroutine can't read it because the iteration condition no longer matches because i + 2 = 11
at that particular iteration and 11 > 10
which causes the iteration to stop and the channel to stay filled.
Now, the other goroutine trying to write into the odd
channel gets blocked as a result and stays blocked forever but since the runtime can easily detect this...it yields a deadlock pretty quickly afterward.
答案2
得分: 2
问题可以通过以下方式解决:
- 删除第二个gofunc的上限(第20行)
- 在写入
even
时使用select
(第28行)
英文:
The problem can be solved by
- Removing the for upper bound for the second gofunc (line 20)
select
ing when writing toeven
(line 28)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论