英文:
Golang,Select, why select deadlock when I add default?
问题
以下是死锁的代码:
package main
import (
"sync"
)
func main() {
var wg sync.WaitGroup
wg.Add(2)
a := make(chan int)
go func() {
defer wg.Done()
for {
var (
name string
x int
ok bool
)
select {
case x, ok = <-a:
name = "a"
default:
println("default error")
}
if !ok {
return
}
println(name, x, ok)
}
}()
go func() {
defer wg.Done()
defer close(a)
for i := 0; i < 10; i++ {
select {
case a <- i:
}
}
}()
wg.Wait()
}
输出结果为:
a 0 true
default error
fatal error: all goroutines are asleep - deadlock!
但是当我从select中移除default时,一切正常。
package main
import (
"sync"
)
func main() {
var wg sync.WaitGroup
wg.Add(2)
a := make(chan int)
go func() {
defer wg.Done()
for {
var (
name string
x int
ok bool
)
select {
case x, ok = <-a:
name = "a"
}
if !ok {
return
}
println(name, x, ok)
}
}()
go func() {
defer wg.Done()
defer close(a)
for i := 0; i < 10; i++ {
select {
case a <- i:
}
}
}()
wg.Wait()
}
输出结果为:
a 0 true
a 1 true
a 2 true
a 3 true
a 4 true
a 5 true
a 6 true
a 7 true
a 8 true
a 9 true
a 0 true
default error
fatal error: all goroutines are asleep - deadlock!
a 0 true
a 1 true
a 2 true
a 3 true
a 4 true
a 5 true
a 6 true
a 7 true
a 8 true
a 9 true
英文:
The below code is deadlock.
package main
import (
"sync"
)
func main() {
var wg sync.WaitGroup
wg.Add(2)
a := make(chan int)
go func() {
defer wg.Done()
for {
var (
name string
x int
ok bool
)
select {
case x, ok = <-a:
name = "a"
default:
println("default error")
}
if !ok {
return
}
println(name, x, ok)
}
}()
go func() {
defer wg.Done()
defer close(a)
for i := 0; i < 10; i++ {
select {
case a <- i:
}
}
}()
wg.Wait()
}
a 0 true
default error
fatal error: all goroutines are asleep - deadlock!
but when I remove default from select, everything is well.
package main
import (
"sync"
)
func main() {
var wg sync.WaitGroup
wg.Add(2)
a := make(chan int)
go func() {
defer wg.Done()
for {
var (
name string
x int
ok bool
)
select {
case x, ok = <-a:
name = "a"
}
if !ok {
return
}
println(name, x, ok)
}
}()
go func() {
defer wg.Done()
defer close(a)
for i := 0; i < 10; i++ {
select {
case a <- i:
}
}
}()
wg.Wait()
}
a 0 true
a 1 true
a 2 true
a 3 true
a 4 true
a 5 true
a 6 true
a 7 true
a 8 true
a 9 true
a 0 true
default error
fatal error: all goroutines are asleep - deadlock!
a 0 true
a 1 true
a 2 true
a 3 true
a 4 true
a 5 true
a 6 true
a 7 true
a 8 true
a 9 true
答案1
得分: 1
当你在select
语句中添加default
子句,并且如果该select
在第二个goroutine的通道发送操作之前运行,那么第一个goroutine将返回并终止。这是因为使用default
时,第一个select
仅仅选择默认情况,因为通道还没有准备好,此时ok
被初始化为false,所以goroutine返回。由于现在没有goroutine从通道中读取数据,第二个goroutine被阻塞,wg.Wait
也被阻塞,因此发生了死锁。
英文:
When you add the default
clause to the select
statement, and if that select runs before the channel send operation of the second goroutine, the first goroutine returns and terminates. This is because with the default
the first select
simply selects the default case because the channel is not ready, at which point ok
is initialized to false, so the goroutine returns. Since now there is no goroutine reading from the channel, the second goroutine blocks, and wg.Wait
also blocks, hence deadlock.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论