go语言day09 通道 协程的死锁
warning:
这篇文章距离上次修改已过190天,其中的内容可能已经有所变动。
在Go语言中,死锁通常发生在多个goroutine竞争同一组资源时,如果每个goroutine都持有某个资源并且等待其他资源,这就可能形成一个死锁的循环等待条件。
下面是一个简单的Go语言代码示例,演示了一个导致死锁的情况:
package main
import (
"fmt"
"time"
)
func main() {
c1 := make(chan bool)
c2 := make(chan bool)
go func() {
fmt.Println("Goroutine 1: 等待 c2...")
<-c2
fmt.Println("Goroutine 1: 得到 c2,等待 1 秒...")
time.Sleep(time.Second)
fmt.Println("Goroutine 1: 发送到 c1")
c1 <- true
}()
go func() {
fmt.Println("Goroutine 2: 等待 c1...")
<-c1
fmt.Println("Goroutine 2: 得到 c1,等待 1 秒...")
time.Sleep(time.Second)
fmt.Println("Goroutine 2: 发送到 c2")
c2 <- true
}()
fmt.Println("主goroutine: 等待10秒...")
time.Sleep(10 * time.Second)
fmt.Println("主goroutine: 结束")
}
这段代码中,我们创建了两个无缓冲的通道c1
和c2
,然后启动了两个goroutine。这两个goroutine相互等待对方发送数据到通道,因此会导致死锁。在主goroutine中,我们等待了10秒钟来模拟一个长时间运行的程序,然后结束。实际上,由于死锁,两个goroutine都不会继续执行。
解决死锁问题的一种方法是确保goroutine不会同时持有多个资源并等待其他资源,从而形成一个循环等待条件。另外,可以使用select
语句和time.After
函数为等待操作添加超时,这样当一个goroutine等待的时间过长时,它会超时退出,从而避免死锁。
例如,可以修改上述代码,为每个通道发送操作添加超时:
package main
import (
"fmt"
"time"
)
func main() {
c1 := make(chan bool)
c2 := make(chan bool)
go func() {
fmt.Println("Goroutine 1: 等待 c2...")
select {
case <-c2:
fmt.Println("Goroutine 1: 得到 c2")
case <-time.After(time.Second):
fmt.Println("Goroutine 1: 超时等待")
return
}
fmt.Println("Goroutine 1: 等待 1 秒...")
time.Sleep(time.Second)
fmt.Println("Goroutine 1: 发送到 c1")
c1 <- true
}()
go func() {
fmt.Println("Goroutine 2: 等待 c1...")
select {
case <-c1:
fmt.Println("Goroutine 2: 得到 c1")
case <-time.After(time.Second):
fmt.Println("Goroutine 2: 超时等待")
return
}
评论已关闭