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

我有一段代码,它对对象的初始化进行了双重检查锁定。

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 不会被不必要地占用。我对么?


收到一只叮咚
浏览 144回答 2
2回答

慕标5832272

如果你没有获取 RLock 来读取syncProducer,那就是数据竞争,因为另一个 goroutine 可能会更新它。如果你假设对指针变量的读/写是原子的,这看起来是无害的——活泼的读syncProducer永远不会导致不正确的行为。如果你不做这个原子假设,如果你不走运的话,读取可能只产生指针的一些字节,你的程序就会崩溃。根据您使用的体系结构、机器字长、编译器版本等,这可能会也可能不会。但这RLock避免了任何担忧。与其显式地乱用 RWLocks,不如使用它(假设目标是懒惰地初始化一个变量):var (    syncOnce sync.Once    syncProducerInternal *syncProducerType)func syncProducer() *syncProducerType {    syncOnce.Do(func() { syncProducerInternal = createSyncKafkaProducer() })    return syncProducerInternal}然后需要同步生产者的代码可以调用该syncProducer()函数来获取它,而永远不会看到 nil 指针。

慕莱坞森

这是必需的,因为检查是只读操作。改为执行 RW 锁是可能的,但这意味着一次只有一个 goroutine 可以进行检查。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go