douqiao6015
2019-08-29 00:53
浏览 274
已采纳

如何两次解锁互斥锁

Is it safe to unlock a mutex twice? My code:

var m sync.RWMutex = sync.RWMutex{}

func Read() {
    m.RLock()
    defer m.RUnlock()

    // Do something that needs lock
    err := SomeFunction1()
    if err != nil {
        return
    }

    m.RUnlock()

    // Do something that does not need lock
    SomeFunction2()

}

I need defer m.RUnlock() for the case SomeFunction1() returns error. But when SomeFunction1() returns without error, m will be unlocked twice by m.RUnlock() and defer m.RUnlock().

Is it safe to unlock the mutex twice? If not, how should I fix my code?

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

两次解锁互斥锁是否安全? 我的代码:

   var m sync.RWMutex = sync.RWMutex {} 
 
func Read(){
 m.RLock()
延迟m.RUnlock()
 
 //执行需要锁定的操作
  err:= SomeFunction1()
如果err!= nil {
 return 
} 
 
 m.RUnlock()
 
 //执行不需要锁定的操作
 SomeFunction2()
 \  n} 
   
 
 

SomeFunction1()返回错误的情况下,我需要推迟m.RUnlock()。 但是,当 SomeFunction1()没有错误返回时, m 将被 m.RUnlock() defer m.RUnlock( )

对互斥锁进行两次解锁安全吗? 如果没有,我应该如何修正我的代码?

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

3条回答 默认 最新

  • doulongti5932 2019-08-29 01:14
    已采纳

    Is it safe for unlocking a mutex twice?

    Nope, you shouldn't unlock the mutex twice. It's a run-time error according to docs.

    RUnlock undoes a single RLock call; it does not affect other simultaneous readers. It is a run-time error if rw is not locked for reading on entry to RUnlock.


    If not, how should I fix my code?

    I would recommend to keep the defer but only m.RUnlock() in case of error. This can easily scale in case you add more function calls between SomeFunction1() and SomeFunction2().

    func Read() {
        var err error
        m.RLock()
        defer func() {
            if err != nil {
                m.RUnlock()
            }
        }()
    
    
        // Do something that needs lock
        err = SomeFunction1()
        if err != nil {
            return
        }
    
        m.RUnlock()
    
        // Do something that does not need lock
        SomeFunction2()
    }
    

    Try it on Go Playground!

    点赞 打赏 评论
  • 中国通信 2019-08-29 01:03

    Unlocking an unlocked Mutex will cause a panic.

    You can simply remove the defer and add it in the if condition:

    var m sync.RWMutex = sync.RWMutex{}
    
    func Read() {
        m.RLock()
    
        // Do something that needs lock
        err := SomeFunction1()
        if (err != nil) {
            m.RUnlock()
            return
        }
    
        m.RUnlock()
    
        // Do something that does not need lock
        SomeFunction2()
    }
    

    Or even better (with a minor impact on readability):

    func Read() {
        m.RLock()
    
        err := SomeFunction1()
        m.RUnlock()
        if (err != nil) {
            return
        }
    
        SomeFunction2()
    }
    
    点赞 打赏 评论
  • dongmanni6916 2019-08-29 01:05

    From godoc:

    It is a run-time error if m is not locked on entry to Unlock.

    So, don't do that.

    Easiest fix is to not use defer unlock, but unlock it at every possible exit. Or, you can also do this, but it is not easy to read:

    func Read() {
        if err := func() {
          m.RLock()
          defer m.RUnlock()
    
          // Do something that needs lock
          err := SomeFunction1()
          if err != nil {
              return err
          }(); err != nil {
            return err
         }
    
        // Do something that does not need lock
        SomeFunction2()
    
    }
    
    点赞 打赏 评论

相关推荐 更多相似问题