go - 如果 goroutine 在获取 Signal() 或 Broadcast() 后无法获取锁,是否会返回等待模式
问题描述
假设我有以下功能。
func acquireResourceAndDoSomething(resourceA, resourceB int) {
lock.Lock()
for !isBothResourceAvailable(resourceA, resourceB) {
isBothResourceAvailable.Wait()
}
isResourceUsed[resourceA] = true
isResourceUsed[resourceB] = true
fmt.Printf("Doing something with resource #%v and #%v\n", resourceA, resourceB)
lock.Unlock()
}
如果我有 3 个 gorountine G1、G2 和 G3。
- G1 需要资源 A 和 B。
- G2 需要资源 B 和 C。
- G3 需要资源 B 和 D。
假设 G3 正在工作并持有资源 B 和 D,而 G1 和 G2 在循环中等待。最终,当 G3 完成并Broadcast()
在释放 B 和 D 后调用时,我希望 G1 和 G2 同时唤醒并同时检查条件。显然,他们中只有 1 人会得到锁继续前进。
我的问题是假设 G1 是第一个获得锁以继续获取资源 A 和 B 的人。如果 G1Unlock()
在没有释放 A 和 B 的情况下调用,G2 会醒来,获得锁并继续,就好像资源 B 和 C 可用一样还是 G2 会再次检查条件以再次进入等待模式?
我是 Golang 的新手,所以非常感谢您的解释:)。
解决方案
Go routine
等待获取锁时,释放时第一次获取。但是如果有一个Go routines pool
,随机一个是获取锁。
但它不知道内部发生了什么。在函数内部,它获得了锁,不管它是否可以等待。它由运行时条件决定。
考虑下面的简单代码
您可以使用两个锁并模拟如下场景。在函数内部,Go 例程必须等待获得另一个锁。它进入函数内部并等待第二个锁。它不知道 lock2 和等待时间,直到获得 lock 1 并在代码之后运行。
package main
import (
"fmt"
"sync"
"time"
)
var lock = new(sync.Mutex)
var lock2 = new(sync.Mutex)
func main() {
wg := new(sync.WaitGroup)
for i := 0; i < 3; i++ {
i := i
wg.Add(1)
go test(wg, i)
}
wg.Wait()
}
func test(wg *sync.WaitGroup, i int) {
defer wg.Done()
fmt.Printf("waiting for lock 1 at G%d\n", i)
t := time.Now().UnixNano()
lock.Lock()
fmt.Printf("acquired lock 1 at G%d after %d nano secs \n\n", i, time.Now().UnixNano()-t)
lock.Unlock()
fmt.Printf("waiting for lock 2 at G%d\n", i)
t = time.Now().UnixNano()
lock2.Lock()
time.Sleep(time.Second)
fmt.Printf("acquired lock 2 at G%d after %d nano secs \n", i, time.Now().UnixNano()-t)
lock2.Unlock()
fmt.Printf("Done at G%d\n\n", i)
}
用于证明行为的随机输出之一。这里所有的 Go 例程都获得了第一个锁,但等待每个 Go 例程解锁第二个锁。所以,直到进入函数它才知道第二个锁
waiting for lock 1 at G2
acquired lock 1 at G2 after 0 nano secs
waiting for lock 2 at G2
waiting for lock 1 at G1
acquired lock 1 at G1 after 0 nano secs
waiting for lock 2 at G1
waiting for lock 1 at G0
acquired lock 1 at G0 after 0 nano secs
waiting for lock 2 at G0
acquired lock 2 at G2 after 1000000000 nano secs
Done at G2
acquired lock 2 at G1 after 2000000000 nano secs
Done at G1
acquired lock 2 at G0 after 3000000000 nano secs
Done at G0
推荐阅读
- java - 如何在不修改现有 java 程序的情况下强制使用 SSLContext TLS 实例
- git - VS Code - 仅搜索当前活动的 git 分支?
- opencv - 图像子部分的翘曲透视变换不对齐
- r - 值为文本的 dcast
- c# - 控制器的POST方法只有一个参数没有被填充,为什么?
- wpf - 单击从第一个窗口的视图模型打开的第二个窗口后,变量值变为空
- arrays - 如何将文件列表复制到目录?
- python - 关于意外将 AWS SSM 参数设置为 String 而不是 SecureString 的问题
- windows-10 - 当前按住 Alt/Ctrl 时,如何在 Alt+Tab/Ctrl+Tab 之后重新映射键?
- javascript - 如何删除许多文件的所有 # 注释行?