Golang中sync.Cond的wait()方法是如何工作的?
Golang中sync.Cond的wait()方法是如何工作的? 请看这段代码:
c.L.Lock()
for i <= 99 {
c.Wait()
}
c.L.Unlock()
在 c.L.Lock() 命令和 c.Wait() 指令之间的某个时刻,其他 goroutine 可能会调用 c.Signal() 或 c.Broadcast()。
如果在 c.Wait() 执行之前,其他 goroutine 就已经调用了 c.Signal() 或 c.Broadcast()……那么这个 c.Wait() 会怎样?它会永远等待吗?之前发出的 c.Signal() 会像在通道中那样被记住吗?
更多关于Golang中sync.Cond的wait()方法是如何工作的?的实战教程也可以访问 https://www.itying.com/category-94-b0.html
谢谢!我怀疑如果Signal()和Broadcast()刚好在调用Wait()之前发生,它们就会丢失。
更多关于Golang中sync.Cond的wait()方法是如何工作的?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
如果一个goroutine在另一个goroutine调用cond.Signal()之后调用cond.Wait(),那么它将不会被唤醒。cond.Signal()只会通知在其运行之前已经调用cond.Wait()的其中一个goroutine。如果两者"同时"调用,调用Wait()的goroutine可能有机会将自己添加到等待列表中,但这并不保证。如果多个goroutine调用Wait(),实现方式会按顺序唤醒它们,但请注意该行为并非API的一部分。此过程不涉及任何通道。
在Go语言的sync.Cond中,Wait()方法的工作机制是:当调用Wait()时,它会释放当前持有的锁,并将当前goroutine放入条件变量的等待队列中,然后阻塞。当其他goroutine调用Signal()或Broadcast()时,会唤醒等待队列中的一个或多个goroutine。被唤醒的goroutine在从Wait()返回前会重新获取锁。
关键点在于:Signal()或Broadcast()的调用只有在Wait()已经执行并将goroutine加入等待队列后才有效。如果在Wait()执行之前就调用了Signal()或Broadcast(),那么这次调用不会对后续的Wait()产生任何影响——它不会"记住"之前的信号。
在你的代码示例中:
- 如果其他goroutine在
c.Wait()执行之前调用了c.Signal()或c.Broadcast(),那么当c.Wait()执行时,它会立即阻塞并等待下一个信号。 - 之前的信号不会保留,条件变量没有像channel那样的缓冲机制来存储信号。
下面是一个完整的示例来说明这个行为:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var mu sync.Mutex
cond := sync.NewCond(&mu)
// Goroutine 1: 等待条件
go func() {
mu.Lock()
fmt.Println("Goroutine 1: 获取锁,开始等待")
// 故意延迟一下,让其他goroutine有机会先发送信号
time.Sleep(100 * time.Millisecond)
cond.Wait() // 这会阻塞,等待信号
fmt.Println("Goroutine 1: 被唤醒,继续执行")
mu.Unlock()
}()
// Goroutine 2: 提前发送信号
go func() {
time.Sleep(50 * time.Millisecond) // 确保在Wait()之前发送信号
fmt.Println("Goroutine 2: 发送信号(在Wait之前)")
cond.Signal()
}()
// Goroutine 3: 稍后再次发送信号来唤醒Goroutine 1
go func() {
time.Sleep(200 * time.Millisecond)
fmt.Println("Goroutine 3: 发送信号(在Wait之后)")
cond.Signal()
}()
time.Sleep(1 * time.Second)
fmt.Println("程序结束")
}
在这个例子中:
- Goroutine 1获取锁后延迟100毫秒才调用
Wait() - Goroutine 2在50毫秒时就调用
Signal()(在Wait()之前) - Goroutine 3在200毫秒时再次调用
Signal()(在Wait()之后)
输出会是:
Goroutine 1: 获取锁,开始等待
Goroutine 2: 发送信号(在Wait之前)
Goroutine 3: 发送信号(在Wait之后)
Goroutine 1: 被唤醒,继续执行
程序结束
可以看到,第一次信号(在Wait()之前)被忽略了,只有第二次信号成功唤醒了Goroutine 1。
因此,在Wait()之前发出的Signal()或Broadcast()不会产生任何效果,Wait()会正常阻塞等待后续的信号。

