首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >互斥量用对了吗?

互斥量用对了吗?
EN

Stack Overflow用户
提问于 2018-08-25 03:53:31
回答 1查看 112关注 0票数 0

我对一个接一个的互斥锁锁定/解锁有点困惑。我使用的是一个RWMutex,当然,所有的goroutine都会有相同的互斥量。

当经常使用互斥锁时,这段代码仍然是竞态保护的吗?

代码语言:javascript
复制
func (r *Redis) RedisDb(dbId DatabaseId) *RedisDb {
    r.Mu().RLock()
    size := len(r.redisDbs) // A
    r.Mu().RUnlock()
    if size >= int(dbId) { // B
        r.Mu().RLock()
        db := r.redisDbs[dbId] // C
        r.Mu().RUnlock()
        if db != nil { // D
            return db
        }
    }
    // E     create db...
}

我会想到的示例情况可能会发生:

  1. gorountine1和goroutine2都在运行这个函数,这两个函数都在点A,所以变量读取是3,条件B是空的,在同一个time
  2. variable读取C,所以条件C是空的,所以条件C是false
  3. now,两个goroutine2将转到E,并创建相同的数据库2次,这是糟糕的< goroutines
  4. both >H218>< true >G219db >

或者在这种情况下,我必须一次性锁定/解锁吗?

代码语言:javascript
复制
func (r *Redis) RedisDb(dbId DatabaseId) *RedisDb {
    r.Mu().Lock()
    defer r.Mu().Unlock()
    size := len(r.redisDbs)
    if size >= int(dbId) {
        db := r.redisDbs[dbId]
        if db != nil {
            return db
        }
    }
    // create db...
}

解决方案

代码语言:javascript
复制
func (r *Redis) RedisDb(dbId DatabaseId) *RedisDb {
    getDb := func() *RedisDb { // returns nil if db not exists
        if len(r.redisDbs) >= int(dbId) {
            db := r.redisDbs[dbId]
            if db != nil {
                return db
            }
        }
        return nil
    }

    r.Mu().RLock()
    db := getDb()
    r.Mu().RUnlock()
    if db != nil {
        return db
    }

    // create db
    r.Mu().Lock()
    defer r.Mu().Unlock()
    // check if db does not exists again since
    // multiple "mutex readers" can come to this point
    db = getDb()
    if db != nil {
        return db
    }
    // now really create it
    // ...
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-08-25 04:00:45

欢迎来到同步世界。您的评估是正确的,第一个实现可能会出现并发问题。对于第二个,这些并发问题被移除,但它是完全锁定的,甚至没有并发读访问的机会。你不必这样做,你可以做一个读锁的初始检查,然后如果检查确定需要创建,建立一个写锁,然后重新检查,如果仍然需要创建,然后解锁。这并不是一个不寻常的构造。它的效率较低(由于执行两次检查),因此您可以决定权衡,主要是基于执行两次检查的代价,以及函数能够在只读路径中操作的频率。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52010914

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档