为啥在使用等待组和通道时会出现死锁?
Posted
技术标签:
【中文标题】为啥在使用等待组和通道时会出现死锁?【英文标题】:why is there deadlock when using wait group and channel in go?为什么在使用等待组和通道时会出现死锁? 【发布时间】:2022-01-10 10:46:47 【问题描述】:我想使用 setter 函数将 0-9 发送到 ch1 通道,然后计算机函数将 ch1 中的数字平方/em>,然后将结果发送到 ch2 频道。但是,运行此代码时我会感到恐慌。谁能解释一下为什么会发生这种情况,我完全糊涂了。
package main
import (
"fmt"
"sync"
)
func setter(ch1 chan int, wg sync.WaitGroup)
for i:= 0; i< 10;i++
fmt.Println("setter:", i)
ch1 <- i
close(ch1)
wg.Done()
func computer(ch1 chan int, ch2 chan int, wg sync.WaitGroup)
for true
tmp, ok := <- ch1
if !ok
fmt.Println("computer: there is no value in ch1")
break
fmt.Println("computer:", tmp*tmp)
ch2 <- tmp*tmp
close(ch2)
wg.Done()
func main()
ch1 := make(chan int,1)
ch2 := make(chan int,1)
var wg sync.WaitGroup
wg.Add(2)
go setter(ch1, wg)
go computer(ch1, ch2, wg)
wg.Wait()
这样的错误:
setter: 0
setter: 1
setter: 2
computer: 0
computer: 1
setter: 3
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [semacquire]:
sync.runtime_Semacquire(0xc000196008)
/usr/local/go/src/runtime/sema.go:56 +0x45
sync.(*WaitGroup).Wait(0xc000196000)
/usr/local/go/src/sync/waitgroup.go:130 +0x65
main.main()
/Users/koujianyuan/Desktop/code/project/go/chan/communication/demo.go:50 +0x13b
goroutine 18 [chan send]:
main.setter(0xc000194000, 0x200000000, 0xc000000000)
/Users/koujianyuan/Desktop/code/project/go/chan/communication/demo.go:16 +0x107
created by main.main
/Users/koujianyuan/Desktop/code/project/go/chan/communication/demo.go:47 +0xdb
goroutine 19 [chan send]:
main.computer(0xc000194000, 0xc000194070, 0x200000000, 0x0)
/Users/koujianyuan/Desktop/code/project/go/chan/communication/demo.go:35 +0x11c
created by main.main
/Users/koujianyuan/Desktop/code/project/go/chan/communication/demo.go:48 +0x12d
【问题讨论】:
在两个函数中使用wg *sync.WaitGroup
并将 &wg
传递给 goroutines。
您没有从任何地方读取ch2
,因此当您将第二个值放入其中时它会阻塞。
【参考方案1】:
出现死锁的原因是你没有从ch2
频道读取。 ch2
通道块,当您第二次尝试将值放入其中时(第一次通过,因为它是 1 的缓冲通道)。当将值放入ch2
通道块时,它也会阻止从ch1
通道中读取值,因此setter
goroutine 不能再将值放入ch1
。
ch1
和 ch2
通道都被阻塞,setter
和 computer
协程都无法完成,从而导致死锁。
Here 是一个工作示例。我添加了从ch2
频道读取的reader
函数。
// The rest of the code is the same except I've changed the functions to use *sync.Waitgroup
func reader(ch chan int, wg *sync.WaitGroup)
defer wg.Done()
for i := range ch
fmt.Println("reading from channel", i)
fmt.Println("reader exiting")
func main()
ch1 := make(chan int, 1)
ch2 := make(chan int, 1)
var wg sync.WaitGroup
wg.Add(3)
go reader(ch2, &wg)
go setter(ch1, &wg)
go computer(ch1, ch2, &wg)
wg.Wait()
【讨论】:
以上是关于为啥在使用等待组和通道时会出现死锁?的主要内容,如果未能解决你的问题,请参考以下文章
为啥立体声 mp3 文件在使用 ffmpeg 从 mp4 转换时会丢失一个通道?