英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论