【问题标题】:Go error: gob: type sync.Mutex has no exported fieldsGo 错误:gob:类型 sync.Mutex 没有导出字段
【发布时间】:2023-03-10 09:04:01
【问题描述】:

我遇到的问题是,如果结构具有导出的 sync.Mutex,我无法将其保存为 gob。如果我使互斥锁未导出(通过不将其大写),一切似乎都有效。我很想知道为什么会这样,并确保吞下未导出的 sync.Mutex 没有其他问题。

我看到在 Google 上有多次点击与 sync.RWMutex 相关的问题,但没有人真正解释为什么会发生这种情况。

package main

import (
    "sync"
    "encoding/gob"
    "os"
    "fmt"
)

func writeGob(filePath string, object interface{}) error {
    file, err := os.Create(filePath)
    defer file.Close()

    if err != nil {
        return err
    }

    encoder := gob.NewEncoder(file)
    err = encoder.Encode(object)
    return err
}

type Dog struct {
    Name string
    GobMux sync.Mutex
}

func main() {
    d := &Dog{Name: "Fido"}
    err := writeGob("./gob", d)
    fmt.Printf("Error: %v\n", err)
}

输出:

错误:gob:类型 sync.Mutex 没有导出字段

【问题讨论】:

  • 关于这个问题有一个未解决的问题:github.com/golang/go/issues/5819
  • 明白了。一个后续问题:当我从 gob 读回 Dog 对象时,看起来互斥锁已解锁,而不管互斥锁在保存到 gob 时的状态如何。我可以指望这种行为吗?
  • 您根本不应该指望反序列化的互斥锁。它在概念上是没有意义的——无论序列化的进程都不能被认为是反序列化它的同一个运行进程,所以互斥锁是没有意义的。它不应包含在序列化中。
  • @Adrian 那么这里的最佳做法是什么?我需要序列化一个包含互斥字段的对象,但看起来没有办法指定 gob 应该忽略一个字段:stackoverflow.com/questions/50595570/…

标签: go mutex gob


【解决方案1】:

Gob 编码

如果我使互斥锁未导出(通过不将其大写),一切似乎都有效。我很想知道这是为什么。

作为Cerise mentioned,有一个open issue,但简而言之,如果您尝试对没有导出字段的结构(例如互斥锁)进行编码,这通常是一个编程错误。

不过,有一些方法可以解决这个特定问题。

您可以将互斥锁设为私有并将锁定/解锁包装在公共函数中,而不是进入结构体来操作互斥锁。例如

func (d *Dog) SetName(name string) {
    d.GobMux.Lock()
    d.Name = name
    d.GobMux.Unlock()
}

你也可以把类型包装起来,把互斥体拉出来:

type Dog struct {
    Name string
}

type DogWrapper struct {
    Dog *Dog
    GobMux sync.Mutex
}

如果您有许多小结构,这相当麻烦,但对于数量较少的更复杂的结构,这可能没问题。

最后,解决这个问题的“正确”方法是编写自己的 GobEncode/Decode 例程。 stdlib 中有一些稀疏的示例,例如 time.GobEncode,但通常这似乎需要相当多的工作。

一般的互斥锁

...并确保在获取未导出的 sync.Mutex 时没有其他问题。

互斥锁与 Go 运行时的进程内内存和调度程序紧密耦合。它们帮助 Go 运行时决定允许哪些 goroutine 读取或写入内存的特定部分,并决定何时可以调度这些 goroutine(即等待互斥锁解锁的 goroutine 在互斥锁解锁之前不会被调度) .

如果您使用 Gob 将数据结构复制到另一个进程,则接收进程的运行时与发送 gob 的进程相比具有完全不同的内部状态,因此互斥锁无法进行逻辑传输。将互斥体复制到另一个进程有点像在火星上使用地球 GPS 坐标。他们只是不匹配。

当我从 gob 读回 Dog 对象时,看起来互斥锁已解锁,而不管互斥锁在保存到 gob 时的状态如何。我可以指望这种行为吗?

正如documentation for Mutex 所述,“互斥锁的零值是未锁定的互斥锁。”所以是的,你可以依赖这种行为。

其他编码器

在我看来,尽管 gob 存在于 stdlib 中,但它并没有受到太多关注,因为还有许多其他成熟的编码选项可用。如果 gob 不能满足您的需求,还有许多其他选项可用 - JSON、Cap'n Proto、net/rpc 等,它们具有不同的特性,可能更适合您。

【讨论】:

    猜你喜欢
    • 2022-10-08
    • 2022-08-04
    • 2019-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多