doukong9316 2018-05-31 23:40
浏览 124
已采纳

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

I am trying to understand whether Mongo locks Go objects.

The first function works fine with the json encoder, however the second function fails fatal error: sync: Unlock of unlocked RWMutex. Is this because mongo.Find is already trying to lock/unlock the state object? Do I need to externally handle race competition for my go objects or does MGO take care of it? I tried reading the source code but I haven't been able to reach a conclusion.

Any would be much appreciated!

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)}

Note: to test it you can just replace the Filestate field with a string map.

  • 写回答

1条回答 默认 最新

  • dragon2025 2018-06-01 07:46
    关注

    First, drop gopkg.in/mgo.v2, it's obsolte, unmaintained. Instead use the community supported fork: github.com/globalsign/mgo.

    Next, you should first read the public, package documentation, and only "revert" to reading the source to clear such things up if the documentation does not offer the answers. But drawing conclusions from the source is always dangerous, as the implementation may change at any time, only what is documented is guaranteed. Documentation of mgo.Session states:

    All Session methods are concurrency-safe and may be called from multiple goroutines.

    This is all the guarantee you have, and all you should depend on. Using methods of mgo.Collection may or may not be safe for concurrent use, so do not do that. When needed, always obtain a "new" collection from the session, as that is safe to be accessed from multiple goroutines.

    And now on to your actual problem.

    Your ApplicationState struct type contains a lock (sync.RWMutex), and you unmarshal your query result into the same ApplicationState value that holds the lock:

    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)
    }
    

    This is a red flag! Don't do this! Unmarshaling into a value may clear any fields, including the lock!

    Yes, you may say it's an unexported field, so the mgo package should not / could not change it. This is true, but the mgo package may decide to create a new ApplicationState value to unmarshal into, and the new value may be assigned to the value pointed by the passed pointer (state).

    If this happens, the newly created ApplicationState will have a lock field being its zero-value, which is an unlocked mutex. And once this happens, the subsequent unlock will obviously fail (panic).

    Solution? Move locks outside of struct values you intend to serialize / deserialize. Or at least don't expect the lock state to transfer along with other fields.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 微信会员卡接入微信支付商户号收款
  • ¥15 如何获取烟草零售终端数据
  • ¥15 数学建模招标中位数问题
  • ¥15 phython路径名过长报错 不知道什么问题
  • ¥15 深度学习中模型转换该怎么实现
  • ¥15 HLs设计手写数字识别程序编译通不过
  • ¥15 Stata外部命令安装问题求帮助!
  • ¥15 从键盘随机输入A-H中的一串字符串,用七段数码管方法进行绘制。提交代码及运行截图。
  • ¥15 TYPCE母转母,插入认方向
  • ¥15 如何用python向钉钉机器人发送可以放大的图片?