你遇到死锁的原因是因为你的代码在使用通道(chan
)时没有正确初始化和使用这些通道。具体来说,以下几点可能导致死锁:
未初始化的通道:
chaS[i]
在你进行<-chaS[i]
操作之前没有被初始化,因此会导致在等待接收的时候出现阻塞,从而导致死锁。同步问题:每次你尝试从
chaS[(i+1)/10] <- struct{}{}
发送一个信号,只有当 i 的值为 9 时,(i+1)/10
会等于 1,否则会产生数组越界错误。这里应该是chaS[(i+1)%10]
或者其他逻辑,以确保索引始终在有效范围内。循环中的 goroutine 调用顺序:你的主线程调用了所有的 goroutine,但是 goroutine 内部的处理并不会立即触发。这意味着如果第一个
go func(i int)
没有完成,则下一个协程无法启动,形成一种等待条件。
下面是修复后的代码示例,可以帮助您理解如何避免这种情况:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
chaS := make([]chan struct{}, 10)
for i := range chaS {
chaS[i] = make(chan struct{}) // 初始化每个通道
}
var global = 1
wg := sync.WaitGroup{}
go func() { // 启动第一个 goroutine
wg.Add(1)
defer wg.Done()
fmt.Println(global)
time.Sleep(time.Second)
global++
for j := 0; j < len(chaS)-1; j++ {
chaS[j] <- struct{}{} // 通知下一个 goroutine 启动
if j == len(chaS)-2 { // 如果已经到达最后一个,关闭最后的通道以防止死锁
close(chaS[j])
}
time.Sleep(time.Millisecond) // 增加一些延迟以确保顺序执行可见
}
}()
for i := 0; i < len(chaS); i++ {
if i > 0 {
<-chaS[i-1] // 等待前一个 goroutine 完成后再继续执行
}
go func(i int) {
defer wg.Done()
fmt.Println(global)
time.Sleep(time.Second)
global++
}(i)
}
wg.Wait()
}
上述代码通过确保每个 channel 都已正确初始化并处理了 goroutines 的启动顺序,以避免任何潜在的死锁情况。请根据实际需求调整代码结构和逻辑。
内容由零声教学AI助手提供,问题来源于学员提问