doutao1939 2018-08-07 08:35
浏览 38
已采纳

可以在锁定之前推迟解锁吗

I'm going over some existing code and see this repeated several times

defer mtx.Unlock()
mtx.Lock()

This looks wrong to me, I much prefer the idiomatic way of deferring the Unlock after performing the Lock but the documentation for Mutex.Lock doesn't specify a situation where the Lock will fail. Therefor the behaviour of the early defer pattern should be identical to the idiomatic way.

My question is: is there a compelling case to say this pattern is inferior? (e.g. the Lock may fail and then the deferred Unlock will panic) and thus the code should be changed or should I leave it as is?

  • 写回答

1条回答 默认 最新

  • duanshan1511 2018-08-07 11:00
    关注

    Short answer:

    Yes, it's OK. The defer call is made after the function returns (well, sort of).

    The longer, more nuanced answer:

    It's risky, and should be avoided. In your 2 line snippet, it's not going to be a problem, but consider the following code:

    func (o *Obj) foo() error {
        defer o.mu.Unlock()
        if err := o.CheckSomething(); err != nil {
            return err
        }
        o.mu.Lock()
        // do stuff
    }
    

    In this case, the mutex may not be locked at all, or worse still: it may be locked on another routine, and you end up unlocking it. Meanwhile yet another routine obtains a lock that it really shouldn't have, and you either get data races, or by the time that routine returns, the unlock call will panic. Debugging this kind of mess is a nightmare you can, and should avoid at all cost.

    In addition to the code looking intuitive and being more error prone, depending on what you're trying to achieve, a defer does come at a cost. In most cases the cost is fairly marginal, but if you're dealing with something that is absolutely time critical, it's often better to manually add the unlock calls where needed. A good example where I'd not use defer is if you're caching stuff in a map[string]interface{}: I'd create a struct with the cached values and an sync.RWMutext field for concurrent use. If I use this cache a lot, the defer calls could start adding up. It can look a bit messy, but it's on a case by case basis. Either performance is what you aim for, or shorter, more readable code.

    Other things to note about defers:

    • if you have multiple defers in a function, the order in which they are invoked is defined (LIFO).
    • Defers can alter the return values of the function you end up calling (if you use named returns)
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥100 嵌入式系统基于PIC16F882和热敏电阻的数字温度计
  • ¥20 BAPI_PR_CHANGE how to add account assignment information for service line
  • ¥500 火焰左右视图、视差(基于双目相机)
  • ¥100 set_link_state
  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化
  • ¥15 Tableau online 嵌入ppt失败
  • ¥100 支付宝网页转账系统不识别账号
  • ¥15 基于单片机的靶位控制系统
  • ¥15 真我手机蓝牙传输进度消息被关闭了,怎么打开?(关键词-消息通知)