英文:
why is there deadlock when using wait group and channel in go?
问题
我想使用setter函数将0-9发送到ch1通道,然后计算函数将ch1通道中的数字平方,然后将结果发送到ch2通道。然而,当运行这段代码时,我遇到了错误。有人可以解释一下为什么会出现这种情况吗?我完全困惑了。
错误信息如下:
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
英文:
I wanna use setter function to send 0-9 into ch1 channel ,and computer function square the number from ch1, then send the result into ch2 channel . however, i get panic when running this code. would anybody explain why this situation happened, i totally confused.
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()
}
the error like this :
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
答案1
得分: 1
死锁的原因是你没有从ch2
通道中读取数据。当你尝试第二次往ch2
通道中放入值时,ch2
通道会被阻塞(第一次可以通过是因为它是一个缓冲通道,容量为1)。当往ch2
通道放入值被阻塞时,它也会阻塞从ch1
通道中读取值,因此setter
goroutine 无法再往ch1
中放入值。
由于ch1
和ch2
通道都被阻塞,setter
和computer
goroutine 都无法完成,导致了死锁。
这里是一个可工作的示例。我添加了一个reader
函数来从ch2
通道中读取数据。
// 除此之外的代码与之前相同,只是我将函数改为使用 *sync.WaitGroup
func reader(ch chan int, wg *sync.WaitGroup) {
defer wg.Done()
for i := range ch {
fmt.Println("从通道中读取", i)
}
fmt.Println("reader 退出")
}
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()
}
这里是示例代码链接。
英文:
The reason why there is a deadlock is that you are not reading from the ch2
channel. The ch2
channel block when you try to put the value in it for the second time (the first time it passes because it is a buffered channel of 1). When putting the value in the ch2
channel blocks, it also blocks reading the value from the ch1
channel, so the setter
goroutine cannot put values in ch1
anymore.
With both ch1
and ch2
channels blocked, both setter
and computer
goroutines cannot finish, which causes a deadlock.
Here is a working example. I've added the reader
function that read from the ch2
channel.
// 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()
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论