我有以下代码。这是一个学习练习,因此它没有做任何明显有用的事情。如果 wg.Add 值为 1,它就会起作用。如果 wg.Add 值为 2,它就会失败。如果我删除通道逻辑,它就会在 wg.Add 值为 2 的情况下起作用。
对我做错的事情有什么想法吗?
package main
import (
"fmt"
"sync"
)
func popMessage(wg *sync.WaitGroup, m *sync.Mutex, i *int, c chan<- int) {
m.Lock()
*i++
c <- *i
m.Unlock()
fmt.Printf("pop %d\n", *i)
wg.Done()
}
func main() {
var wg sync.WaitGroup
var m sync.Mutex
var intPtr *int
c := make(chan int, 1)
wg.Add(2)
intPtr = new(int)
*intPtr = 1
go popMessage(&wg, &m, intPtr, c)
go popMessage(&wg, &m, intPtr, c)
go popMessage(&wg, &m, intPtr, c)
wg.Wait()
fmt.Printf("final %d\n", *intPtr)
for x := range c {
fmt.Printf("channel %d\n", x)
}
}
该
wg.Wait()
函数将阻塞,直到WaitGroup
计数器达到零。在您的例子中,您使用 初始化计数器wg.Add(2)
,这意味着wg.Wait()
将等待wg.Done()
被调用两次,然后才能继续。您还创建了一个容量为 1 的缓冲通道
c := make(chan int, 1)
( )。这意味着该通道只能在其缓冲区中保存一个值。一旦缓冲区已满,任何其他发送操作 (c <- value
) 都将被阻塞,直到 goroutine 从通道接收到一个值 (<-c
),从而释放缓冲区中的空间。在您的代码中,将一个值发送到通道后,缓冲区将变满。任何后续发送操作(
c <- *i
)都将阻塞,因为通道没有可用空间。因此,只有一个 goroutine 成功调用wg.Done()
,而其他 goroutine 仍处于阻塞状态,等待发送其数据。这会导致死锁:
wg.Wait()
正在等待第二个wg.Done()
调用,但第二个 goroutine 卡在尝试将数据发送到通道时。因此,您的程序无限期挂起。使固定:
并在 for 循环上方和下方写下此代码
wg.Wait()
: