Go语言使用sync包与channel出现Deadlock错误,请求排查代码问题
Go goroutine与channel死锁问题排查
问题背景
我在学习goroutine时编写了一段Go代码,使用sync包与channel实现了如下逻辑:
package main import ( "fmt" "sync" ) var waitGroup sync.WaitGroup func writeToChannel(c chan int, x int) { fmt.Println(x) c <- x // c라는 채널에 x값을 쓴다. fmt.Println(x) close(c) // 통신 종료 waitGroup.Done() } func main() { c := make(chan int) waitGroup.Add(1) go writeToChannel(c, 10) waitGroup.Wait() }
编译运行后出现死锁错误:
junbeomhan@acd:~/Documents/workspace/go/src/go-routine$ go run writeCh.go 10 fatal error: all goroutines are asleep - deadlock! goroutine 1 [semacquire]: sync.runtime_Semacquire(0xc000014270?) /usr/local/go/src/runtime/sema.go:62 +0x27 sync.(*WaitGroup).Wait(0x0?) /usr/local/go/src/sync/waitgroup.go:116 +0x4b main.main() /home/junbeomhan/Documents/workspace/go/src/go-routine/writeCh.go:22 +0x85 goroutine 6 [chan send]: main.writeToChannel(0x0?, 0xa) /home/junbeomhan/Documents/workspace/go/src/go-routine/writeCh.go:12 +0x75 created by main.main /home/junbeomhan/Documents/workspace/go/src/go-routine/writeCh.go:21 +0x79 exit status 2
请问这段代码存在什么问题?
问题分析与解决
核心问题:无缓冲channel的阻塞特性引发死锁
你创建的是无缓冲channel(make(chan int)),这类channel的发送操作c <- x会一直阻塞,直到有其他goroutine对该channel执行接收操作。
代码里main goroutine启动子goroutine后立刻调用waitGroup.Wait()进入等待状态,没有任何goroutine去接收channel里的数据,导致子goroutine卡在c <- x这一行无法继续执行,自然也没法调用waitGroup.Done()。最终两个goroutine都陷入阻塞,触发死锁。修复方案
方案一:在main goroutine中添加channel接收操作,放在waitGroup.Wait()之前:func main() { c := make(chan int) waitGroup.Add(1) go writeToChannel(c, 10) <-c // 接收channel中的数据,让子goroutine的发送操作完成 waitGroup.Wait() }方案二:使用带缓冲的channel,缓冲大小至少为1,这样发送操作不会阻塞:
func main() { c := make(chan int, 1) // 创建缓冲大小为1的channel waitGroup.Add(1) go writeToChannel(c, 10) waitGroup.Wait() }
内容的提问来源于stack exchange,提问作者한준범
相关产品推荐
相关产品推荐

