【发布时间】:2019-01-08 13:34:04
【问题描述】:
我有一段来自this website 的代码,它对对象的初始化进行了双重检查锁定。
func checkSyncProducer() {
mutex.RLock()
if syncProducer == nil {
mutex.RUnlock()
mutex.Lock()
defer mutex.Unlock()
if syncProducer == nil {
syncProducer = createSyncKafkaProducer() //this func will initialize syncProducer.
}
} else {
defer mutex.RUnlock()
}
}
这段代码在第一次零检查之前有mutex.RLock()。
为什么需要这样做? (它在页面中进行了解释,但我无法理解)并且它不会增加开销,因为每次调用 checkSyncProducer 时都会获取并释放读锁。
在获取读锁之前是否应该再进行一次 nil 检查,例如:
func checkSyncProducer() {
if syncProducer == nil {
mutex.RLock()
if syncProducer == nil {
mutex.RUnlock()
mutex.Lock()
defer mutex.Unlock()
if syncProducer == nil {
createSyncKafkaProducer()
}
} else {
defer mutex.RUnlock()
}
}
}
第一次 nil 检查将确保 RLock 不会被不必要地使用。我对么?
【问题讨论】:
-
hmm,我很想知道人们要说什么 - 我看起来不需要 RLock,nil 检查就足够了 - 也许我遗漏了一些东西,这可能取决于更广泛的背景,但我想想只要你检查 nil,获取锁,然后检查它仍然是 nil(以防另一个线程在那微秒内初始化)它应该没问题
-
最后一句没看懂。为什么你认为应该有一个额外的零检查?
-
认为另一个线程可能会在检查 nil 和获取锁之间的瞬间初始化,尽管您似乎建议您的答案中需要 rlock
-
但是已经有第二次 nil 检查了...
-
第二种实现容易受到锁应该防止的竞争条件的影响。
syncProducer在没有至少一个读锁的情况下不能被读取,并且在没有写锁的情况下不能被分配。
标签: go