我试图了解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字段替换为字符串映射即可。

最佳答案

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

接下来,您应该首先阅读公共(public)的,打包的文档,并且如果文档没有提供答案,则只能“还原”阅读源以清除这些内容。但是从源头得出结论总是很危险的,因为实现可能随时更改,因此只能保证所记录的内容。 mgo.Session 状态的文档:



这是您所拥有的所有保证,也是您应依靠的所有保证。使用 mgo.Collection 的方法可以并发使用,但不一定安全,因此不要这样做。必要时,请始终从 session 中获取"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字段作为其零值,该字段是未锁定的互斥量。一旦发生这种情况,随后的解锁显然会失败(紧急)。

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

关于mongodb - Golang MGO模块是否锁定或解锁Go对象?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50634264/

10-16 20:50