首页 > 解决方案 > Golang MGO 模块是否锁定或解锁 Go 对象?

问题描述

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

标签: mongodbgostructmutexmgo

解决方案


首先, drop gopkg.in/mgo.v2,它已经过时,没有维护。而是使用社区支持的 fork: github.com/globalsign/mgo

接下来,您应该首先阅读公共的、打包的文档,如果文档没有提供答案,则仅“恢复”阅读源代码以清除此类内容。但是从源头得出结论总是很危险的,因为实施可能随时发生变化,只有记录在案的内容才能得到保证。状态文件mgo.Session

所有 Session 方法都是并发安全的,可以从多个 goroutine 调用。

这是您拥有的所有保证,也是您应该依赖的所有保证。使用 of 的方法mgo.Collection对于并发使用可能安全,也可能不安全,所以不要那样做。需要时,始终从会话中获取“新”集合,因为可以安全地从多个 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为零值的字段,这是一个未锁定的互斥体。而一旦发生这种情况,后续的解锁显然会失败(恐慌)。

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


推荐阅读