golang下面代码为什么会死锁


type UserTable struct {
    sync.RWMutex
    //deadlock.RWMutex

    table map[int]string
}

func NewUserTable()*UserTable{
    return &UserTable{
        table:make(map[int]string),
    }
}

func (userTable *UserTable)GetUser(i int)string{
    userTable.RLock()
    defer userTable.RUnlock()
    if name, exist := userTable.table[i]; exist{
        return name
    }
    return ""
}

func (userTable *UserTable)GetTable()map[int]string{
    userTable.RLock()
    defer userTable.RUnlock()
    newMap := make(map[int]string)
    for seatID, _ := range userTable.table{
        newMap[seatID] = userTable.GetUser(seatID)
    }
    return newMap
}

func (userTable *UserTable)SetUser(i int, name string){
    userTable.Lock()
    defer userTable.Unlock()
    if len(userTable.table) >= 100{
        userTable.table = make(map[int]string)
    }
    userTable.table[i] = name
}


func main() {
    userTable := NewUserTable()
    go func() {
        i := 0
        for{
            if i % 1000 == 0{
                fmt.Printf("%v\n", userTable.GetTable())
            }
            userTable.SetUser(i, fmt.Sprintf("%v", i))
            i++
        }

    }()

    go func(){
        for{
            userTable.GetTable()
            time.Sleep(100*time.Millisecond)
        }

    }()
    select {

    }
    //time.Sleep(100* time.Second)
}
阅读 1.9k
1 个回答

问题在于 GetTable 方法:在该方法中你已经加锁来保护 table 中的数据了,直接操作数据就行了,不应该画蛇添足地调用 GetUser 方法,因为 GetUser 中也要加锁

结果就导致,在第二个 go func 中 GetTable 的两次 RLock 之间,第一个 go func 中的 SetUser 进行 RWLock,此时就会死锁


解决方法很简单,在 GetTable 中直接操作 table,不要再去调用 GetUser 了,

如果从 table 获取值的操作确实在 GetUser 和 GetTable 中都存在,并且较为复杂,你可以再写一个 非导出 的 _help 方法来实现这个功能,这个方法里不要加锁,然后 GetUser 和 GetTable 都调用这个函数

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题