为了账号安全,请及时绑定邮箱和手机立即绑定

双重检查 golang 中的锁定 - 为什么需要 mutex.RLock()?

双重检查 golang 中的锁定 - 为什么需要 mutex.RLock()?

Go
收到一只叮咚 2023-06-01 14:05:34
我有一段代码,它对对象的初始化进行了双重检查锁定。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()第一次 nil 检查之前。为什么需要这样?(它在页面中有解释,但我无法理解)并且它不会增加开销,因为每次调用 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 不会被不必要地占用。我对么?
查看完整描述

2 回答

?
慕标5832272

TA贡献1966条经验 获得超4个赞

如果你没有获取 RLock 来读取syncProducer,那就是数据竞争,因为另一个 goroutine 可能会更新它。


如果你假设对指针变量的读/写是原子的,这看起来是无害的——活泼的读syncProducer永远不会导致不正确的行为。如果你不做这个原子假设,如果你不走运的话,读取可能只产生指针的一些字节,你的程序就会崩溃。


根据您使用的体系结构、机器字长、编译器版本等,这可能会也可能不会。但这RLock避免了任何担忧。


与其显式地乱用 RWLocks,不如使用它(假设目标是懒惰地初始化一个变量):


var (

    syncOnce sync.Once

    syncProducerInternal *syncProducerType

)


func syncProducer() *syncProducerType {

    syncOnce.Do(func() { syncProducerInternal = createSyncKafkaProducer() })

    return syncProducerInternal

}

然后需要同步生产者的代码可以调用该syncProducer()函数来获取它,而永远不会看到 nil 指针。


查看完整回答
反对 回复 2023-06-01
?
慕莱坞森

TA贡献1810条经验 获得超4个赞

这是必需的,因为检查是只读操作。改为执行 RW 锁是可能的,但这意味着一次只有一个 goroutine 可以进行检查。



查看完整回答
反对 回复 2023-06-01
  • 2 回答
  • 0 关注
  • 143 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信