我试图了解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字段即可。
答案 0 :(得分:2)
首先,丢弃gopkg.in/mgo.v2
,它是无耻的,没有维护。而是使用社区支持的fork:github.com/globalsign/mgo
。
接下来,您应首先阅读公开的软件包文档,如果文档没有提供答案,则应该“恢复”阅读源代码以清除此类内容。但是从源头得出结论总是很危险的,因为实施可能随时改变,只保证记录的内容。 mgo.Session
州的文件:
所有Session方法都是并发安全的,可以从多个goroutine中调用。
这是您拥有的所有保证,您应该依赖的一切。使用mgo.Collection
的方法对于并发使用可能是安全的,也可能不安全,所以不要这样做。在需要时,始终从会话中获取“新”集合,因为可以安全地从多个goroutines访问。
现在问你的实际问题。
您的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
字段为零值,这是一个未锁定的互斥锁。一旦发生这种情况,后续解锁显然会失败(恐慌)。
解决方案?将锁定移到要打算序列化/反序列化的结构值之外。或者至少不要指望锁定状态与其他字段一起传输。