php小编小新在这里为大家介绍一种常见的并发编程问题——死锁。死锁是指所有goroutine都进入了睡眠状态,即使使用了等待组等机制,也无法继续执行下去。这种情况下,所有的goroutine都无法向前推进,导致程序陷入无限等待的状态。在并发编程中,避免死锁是非常重要的,我们需要了解其原因和解决方案,以确保程序的正常运行。
问题内容
我正在学习 go 并发,我希望两个 go 例程能够继续相互通信,同时通过通道传递更新的值。一个加 2,另一个减 1。代码和输出如下:
这段代码有什么问题?
package main
import (
"fmt"
"sync"
"time"
)
var wg sync.waitgroup
func addtwo(r chan int, e chan int) {
val := <-r
fmt.println("at recieved: ", val)
time.sleep(1 * time.second)
e <- val + 2
}
func subtractone(r chan int, e chan int) {
val := <-r
fmt.println("so recieved: ", val)
time.sleep(1 * time.second)
e <- val - 1
}
func main() {
ch := make(chan int)
ch2 := make(chan int)
wg.add(1)
go addtwo(ch, ch2)
wg.add(1)
go subtractone(ch2, ch)
ch <- 1
wg.wait()
}
输出:
AT Recieved: 1
SO Recieved: 3
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [semacquire]:
sync.runtime_Semacquire(0x4b2de8?)
/usr/lib/go-1.18/src/runtime/sema.go:56 +0x25
sync.(*WaitGroup).Wait(0x0?)
/usr/lib/go-1.18/src/sync/waitgroup.go:136 +0x52
main.main()
然后它就退出了。
为什么 goroutine 不会永远交换值,即使我没有在 goroutine 中调用 wg.done() ?
解决方法
您启动的两个 goroutine 都只接收一个值并发送一个值,然后结束。从那里开始,只有 main
goroutine,在 wg.wait()
处被阻止,因为你从未调用 wg.done()
。
你忘记使用(n无限)循环:
func addtwo(r chan int, e chan int) {
for {
val := <-r
fmt.println("at recieved: ", val)
time.sleep(1 * time.second)
e <- val + 2
}
}
func subtractone(r chan int, e chan int) {
for {
val := <-r
fmt.println("so recieved: ", val)
time.sleep(1 * time.second)
e <- val - 1
}
}
通过此更改,您的应用程序将永远运行,输出为:
AT Recieved: 1
SO Recieved: 3
AT Recieved: 2
SO Recieved: 4
AT Recieved: 3
SO Recieved: 5
AT Recieved: 4
....
以上就是死锁 - 所有 goroutine 都处于睡眠状态(即使使用等待组)的详细内容,更多请关注编程网其它相关文章!