Golang MGO 模块是否锁定或解锁 Go 对象?

Does the Golang MGO module lock or unlock Go objects?

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

第一个函数在 json 编码器上运行良好,但第二个函数失败 fatal error: sync: Unlock of unlocked RWMutex。这是因为 mongo.Find 已经在尝试 lock/unlock 状态对象了吗?我是否需要在外部处理我的围棋对象的比赛或 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 字段替换为字符串映射即可。

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

接下来,您应该先阅读 public 软件包文档,如果文档没有提供答案,则只 "revert" 阅读源代码以清除这些问题。但从源头上得出结论总是很危险的,因为实施可能随时发生变化,只有记录在案的才能得到保证。 mgo.Session 的文档说明:

All Session methods are concurrency-safe and may be called from multiple goroutines.

这就是你的全部保障,也是你该依赖的。使用 mgo.Collection 的方法对于并发使用可能安全也可能不安全,所以不要那样做。需要时,始终从会话中获取 "new" 集合,因为可以安全地从多个 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 字段作为其零值,这是一个未锁定的互斥量。而一旦出现这种情况,后续的解锁显然会失败(panic)。

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