很抱歉没有直接回答您的问题:
IMHO,在Go中实现递归锁的最佳方法是不实现它们,而是重新设计代码,使其一开始就不需要它们.我认为,对它们的渴望很可能表明对某些(此处未知)问题采用了错误的方法.
作为上述主张的间接"证据":对于涉及互斥锁的一些常见情况,递归锁是不是一种常见的/正确的方法,它迟早会包含在标准库中.
最后,最后但并非最不重要的一点:Go开发团队的罗斯 Cox在这里写道:
递归(也称为可重入)互斥锁不是一个好主意. 使用互斥锁的根本原因是互斥锁 保护不变量,可能是内部不变量,如 "p.Prev.Next==p表示环的所有元素",或者可能 外部不变量,如"我的局部变量x等于p.Prev".
锁定互斥锁断言"我需要保持不变量" 也许"我会暂时打破这些不变量." 释放互斥声明"我不再依赖那些 不变量"和"如果我 destruct 了它们,我就恢复了它们."
了解互斥锁保护不变量对于 标识哪里需要互斥锁,哪里不需要. 例如,共享计数器是否使用ATOM更新 递增和递减指令需要互斥锁吗? 这取决于不变量.如果唯一不变的是 计数器在i递增和d递减之后具有值i-d, 那么说明书的气势性就能确保 不变量;不需要互斥锁.但如果柜台一定要 与某些其他数据 struct 同步(也许它也算 列表上的元素数量),然后是 单打独斗是不够的.一些其他的东西, 通常是互斥体,必须保护更高级别的不变量. 这就是为什么Go中的 map 操作不是 保证是原子的:它会增加费用,而不是 在典型 case 中受益.
让我们来看看递归互斥锁. 假设我们有如下代码:
func F() {
mu.Lock()
... do some stuff ...
G()
... do some more stuff ...
mu.Unlock()
}
func G() {
mu.Lock()
... do some stuff ...
mu.Unlock()
}
通常情况下,打电话给mu时.Lock返回调用代码
递归互斥实现将使G的mu.锁
递归互斥锁不保护不变量. 互斥锁只有一个任务,而递归互斥锁不做这件事.
还有一些更简单的问题,比如如果你写
func F() {
mu.Lock()
... do some stuff
}
您永远不会在单线程测试中找到错误. 但这只是更大问题的特例, 那就是他们根本不能保证 互斥锁要保护的不变量.
如果您需要实现可以调用的功能 不管是否持有互斥体,要做的最清楚的事情就是 就是写两个版本.例如,代替上面的G, 您可以这样写:
// To be called with mu already held.
// Caller must be careful to ensure that ...
func g() {
... do some stuff ...
}
func G() {
mu.Lock()
g()
mu.Unlock()
}
或者如果它们都是未出口的,g和glock.
我确信我们最终会需要TryLock;请随意 请为那件事给我们寄一个提货箱.超时锁定似乎不那么重要 但是如果有一个干净的实现(我不知道有一个) 那也许就没问题了.请不要寄出这样的提单. 实现递归互斥锁.
递归互斥只是一个错误,只不过
罗斯