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

在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?

图片转代码服务由CSDN问答提供 功能建议

我从此网站,它已对对象的初始化进行了双重检查锁定。 \ n

  func checkSyncProducer(){
 Mutex.RLock()
如果syncProducer == nil {
 Mutex.RUnlock()
 Mutex.Lock()
延迟Mutex.Unlock(  )
 if syncProducer == nil {
 syncProducer = createSyncKafkaProducer()//此函数将初始化syncProducer。
} 
}否则{
延迟mutex.RUnlock()
} 
} 
   
 
 

此代码段在进行第一个nil检查之前具有 mutex.RLock()

为什么要这样做? (在页面中对此进行了解释,但我不明白),而且由于每次checkSyncProducer称为读取锁定都会被使用并释放,因此它不会增加开销。

在获取读锁之前是否应该再进行一次nil检查:

  func checkSyncProducer(){
如果syncProducer == nil  {
mutex.RLock()
,如果syncProducer == nil {
 Mutex.RUnlock()
 Mutex.Lock()
延迟互斥锁。Unlock()
,如果syncProducer == nil {
 createSyncKafkaProducer(  )
} 
} else {
延迟mutex.RUnlock()
} 
} 
} 
   
 
 

第一个nil检查将确保RLock 没有不必要的采取。 我对么?

  • 写回答
  • 好问题 提建议
  • 关注问题
  • 收藏
  • 邀请回答

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.

    已采纳该答案
    评论
    解决 无用
    打赏 举报
  • duancong6937 2019-01-08 13:51

    It's required because the check is a read-only operation. Doing a RW lock instead would be possible, but would mean that only one goroutine at a time could do the check.

    评论
    解决 无用
    打赏 举报

相关推荐 更多相似问题