我试图了解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/