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

时间:2018-05-31 23:40:57

标签: mongodb go struct mutex mgo

我试图了解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字段即可。

1 个答案:

答案 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字段为零值,这是一个未锁定的互斥锁。一旦发生这种情况,后续解锁显然会失败(恐慌)。

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