go - sync.Cond 是如何工作的?
问题描述
我试图了解如何工作sync.Cond
,但它对我不起作用。我的代码
c := sync.NewCond(&sync.Mutex{})
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
c.L.Lock()
defer c.L.Unlock()
c.Wait()
fmt.Println("I'm created")
}()
c.Signal()
wg.Wait()
我总是陷入僵局,但如果我在什么都没有出现defer
之前删除,但wg.Done()
在这种情况下我不会收到错误。我看过其他例子,但它们是不同的。我想使用我的示例了解基本思想 sync.Cond。我不知道这里哪里出错了,因为 goroutine 运行并且没关系,然后它等待一个信号,但是在主 goroutine 我这样做 c.Signal() ,因此我希望 goroutine 能够恢复,但它不会发生......
解决方案
作为一般规则,1当你使用一个sync.Cond
变量时,你需要做两件事:
- 互斥体,和
- 互斥锁正在保护的数据结构。
在该数据结构中,您需要有一些变量来告诉您条件本身已满足或未满足。
这导致这种形式的代码:
type whatever struct {
ready bool
done bool
input string
result string
lock sync.Mutex
cond *sync.Cond
}
func doStuff(p *whatever) {
p.lock.Lock()
defer p.lock.Unlock()
for !p.ready && !p.done {
p.cond.Wait()
}
fmt.Printf("working on thing with input=%q\n", p.input)
p.result = "all done now"
p.done = true
p.cond.Signal()
}
func waitDone(p *whatever) {
p.lock.Lock()
defer p.lock.Unlock()
for !p.done {
p.cond.Wait()
}
}
然后您可以从其他地方使用它,例如:
var obj whatever
obj.cond = sync.NewCond(&obj.lock)
go doStuff(&obj)
obj.lock.Lock()
obj.input = "some input"
obj.ready = true // object is now ready to be worked-on
obj.lock.Unlock()
obj.cond.Signal()
waitDone(&obj)
fmt.Printf("obj is done, result is %q\n", obj.result)
这里有一个完整的例子。
现在,正如所写的,没有理由在sync.Cond
这里使用 a 。对于这种情况,仅使用互斥锁就足够了。sync.Cond
当多个并发例程需要等待某个事件时,我们确实使用了一个。例如,多个 goroutine 可能需要该对象:一个人应该完成工作,然后应该将该对象标记为就绪,并使用广播提醒所有等待该对象的人。在这种情况下,doStuff()
将以p.cond.Broadcast()
而不是结束p.cond.Signal()
。
在其他一些情况下,我们可能有一个对象在不同的 goroutine 之间进行乒乓操作。一个或多个 goroutine 正在或至少可能正在等待该对象。其中一个——让我们称之为这个特定的 goroutine Fred——获得了它的控制权并在对象上做一些有限的工作,然后声明这个goroutine 已经完成。Fred 将对象恢复到合适的状态(完成了一些但不是全部工作)并调用p.cond.Signal()
,这会唤醒其他两个都在等待对象的 goroutine 中的一个。无论哪个被唤醒,都会获取该对象,对其进行更多工作,然后将其恢复到合适的状态并调用p.cond.Signal()
以向其他任何人发出等待的信号。
最终,工作全部完成,完成工作的人设置p.done
并打电话p.cond.Broadcast()
提醒所有可能处理p
该工作的人p
现在已经完成。
条件变量比简单的互斥锁更灵活,但需要更多的思考和关注。如果一个简单的互斥锁就可以完成工作,通常最好只使用互斥锁。
1在某些情况下您可以违反此规则,但如果您准备好考虑这些情况,您一开始就不会遇到此问题。
推荐阅读
- python - 是否可以将预训练的 lda 模型加载到 gensim 中?
- glob - 全局匹配在 Storybook 配置中不起作用?
- go - golang json.Unmarshal 到 struct []byte
- binary - 如何使用 C 语言从原始图像文件中获取秘密位?
- html - 对齐页脚引导卡片组的顶部
- python - 如何使用 Python 解析数百个具有相同 JSON 数据类型的网站?
- python - 无法导入 python 3.5.9
- mysql - MySQL中浮点数据类型的问题
- python - 是否有类似于 Matlab 格式的 python 函数或扩展?
- spring-boot - 在 Spring Boot Actuator 上显示 Hibernate Search 统计信息