dpvv37755 2019-01-08 13:34
浏览 331
已采纳

在golang中仔细检查了锁定-为什么需要mutex.RLock()?

I have a piece of code from this website which has double checked locking for initialization of an object.

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()
    }
}

This piece of code has mutex.RLock() before first nil check.

Why is that required? (it is explained in the page but I couldn't understand) And doesn't it add overhead becuase everytime checkSyncProducer is called read lock will be taken and released.

Should there be one more nil check before acquiring read lock like:

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()
        }
    }
}

First nil check will ensure that RLock is not taken unnecessarily. Am I correct?

  • 写回答

2条回答 默认 最新

  • douou2026 2019-01-08 14:24
    关注

    If you don't acquire a RLock to read syncProducer, it's a data race, since another goroutine may update it.

    If you assume reads/writes to pointer variables are atomic, this looks harmless -- the racy read of syncProducer can never cause incorrect behavior. If you don't make this atomic assumption, the read could produce just some of the bytes of the pointer if you're unlucky, and your program would crash.

    It may or may not be possible depending on the architecture, machine word size, compiler version, etc. that you're using. But the RLock avoids any concern.

    Rather than explicitly mess around with RWLocks, it's probably better to use this (assuming the goal is to lazily initialize a variable):

    var (
        syncOnce sync.Once
        syncProducerInternal *syncProducerType
    )
    
    func syncProducer() *syncProducerType {
        syncOnce.Do(func() { syncProducerInternal = createSyncKafkaProducer() })
        return syncProducerInternal
    }
    

    Then code that needs the sync producer can call the syncProducer() function to get it, and never see a nil pointer.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥20 西门子S7-Graph,S7-300,梯形图
  • ¥50 用易语言http 访问不了网页
  • ¥50 safari浏览器fetch提交数据后数据丢失问题
  • ¥15 matlab不知道怎么改,求解答!!
  • ¥15 永磁直线电机的电流环pi调不出来
  • ¥15 用stata实现聚类的代码
  • ¥15 请问paddlehub能支持移动端开发吗?在Android studio上该如何部署?
  • ¥20 docker里部署springboot项目,访问不到扬声器
  • ¥15 netty整合springboot之后自动重连失效
  • ¥15 悬赏!微信开发者工具报错,求帮改