【问题标题】:Does the Golang MGO module lock or unlock Go objects?Golang MGO 模块是否锁定或解锁 Go 对象?
【发布时间】:2018-05-31 23:40:57
【问题描述】:

我试图了解 Mongo 是否锁定 Go 对象。

第一个函数适用于 json 编码器,但第二个函数失败 fatal error: sync: Unlock of unlocked RWMutex。这是因为 mongo.Find 已经在尝试锁定/解锁状态对象吗?我需要在外部处理我的围棋对象的比赛还是由 MGO 处理?我尝试阅读源代码,但无法得出结论。

任何将不胜感激!

import (
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
"io"
"sync"
"encoding/json"
)

type ApplicationState struct {
    FileStates map[string]FileState     `json:"fileStates" bson:"fileStates"` 
    lock       sync.RWMutex             `json:"-" bson:"-"`
}

func (state *ApplicationState) ReadState(reader io.Reader) error {
    state.lock.Lock()
    defer state.lock.Unlock()
    return json.NewDecoder(reader).Decode(state)}

func (state *ApplicationState) ReadStateMGO(c *mgo.Collection) error {
    state.lock.Lock()
    defer state.lock.Unlock()
    return c.Find( bson.M{} ).Select( bson.M{"_id": 0} ).One(state)}

注意:要对其进行测试,您只需将 Filestate 字段替换为字符串映射即可。

【问题讨论】:

    标签: mongodb go struct mutex mgo


    【解决方案1】:

    首先,删除gopkg.in/mgo.v2,它已经过时,无人维护。而是使用社区支持的分支:github.com/globalsign/mgo

    接下来,您应该首先阅读公共的、打包的文档,如果文档没有提供答案,则仅“恢复”阅读源代码以清除此类内容。但是从源头得出结论总是很危险的,因为实施可能随时发生变化,只有记录在案的内容才能得到保证。 mgo.Session 的文档说明:

    所有 Session 方法都是并发安全的,可以从多个 goroutine 中调用。

    这是您拥有的所有保证,也是您应该依赖的所有保证。使用mgo.Collection 的方法对于并发使用可能安全也可能不安全,所以不要这样做。需要时,始终从会话中获取“新”集合,因为可以安全地从多个 goroutine 访问。

    现在谈谈你的实际问题。

    您的 ApplicationState 结构类型包含一个锁 (sync.RWMutex),您将查询结果解组为持有锁的同一 ApplicationState 值:

    func (state *ApplicationState) ReadStateMGO(c *mgo.Collection) error {
        state.lock.Lock()
        defer state.lock.Unlock()
        return c.Find( bson.M{} ).Select( bson.M{"_id": 0} ).One(state)
    }
    

    这是一个危险信号!不要这样做!解组为一个值可能会清除任何字段,包括锁!

    是的,您可能会说这是一个未导出的字段,因此 mgo 包不应该/不能更改它。这是真的,但mgo 包可能决定创建一个新的ApplicationState 值来解组,并且新值可以分配给传递的指针(state)所指向的值。

    如果发生这种情况,新创建的 ApplicationState 将有一个 lock 字段作为其零值,这是一个未锁定的互斥体。而一旦发生这种情况,后续的解锁显然会失败(恐慌)。

    解决方案?将锁移到您打算序列化/反序列化的结构值之外。或者至少不要期望锁定状态会与其他字段一起转移。

    【讨论】:

    • 非常感谢您的详细回答和建议最佳实践! :)
    • 另一个问题,在这种情况下甚至需要锁吗? Select(..) 或 Upsert() 是否会锁定状态/结果变量,直到操作完成?我正在使用多线程
    • @SemihSezer 不,他们不会锁定他们解组的值。如果你想同时从多个 goroutine 中读取/写入相同的值,你需要自己同步它们。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-20
    • 1970-01-01
    • 2010-12-07
    • 2021-09-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多