【问题标题】:Why do the Go-generated protobuf files contain mutex locks?为什么 Go 生成的 protobuf 文件包含互斥锁?
【发布时间】:2020-10-03 11:37:14
【问题描述】:

在 go 中工作和生成 protobuf 存根时,我偶然发现了这个有趣的问题。

每当我尝试按值复制消息的结构时,我都会收到以下警告:

调用 state.world.script.HandleEvent 复制锁值:throat/server/messages.PlayerDialogeStatus contains google.golang.org/protobuf/internal/impl.MessageState contains sync.Mutex copylocks

虽然我理解为什么按值复制互斥锁是错误的,但我开始想知道为什么他们一开始就在那里。

因此我的问题是:为什么 go 生成的 protobuf 文件包含放置在消息结构上的互斥锁,特别是在 MessageState 结构上?

或者:在生成的 protobuf 消息结构上找到的 MessageState 结构中放置互斥锁的目的是什么?

【问题讨论】:

    标签: go protocol-buffers mutex


    【解决方案1】:

    impl.MessageState 仅嵌入在具体消息中,而不是在实现原始消息的生成结构中。

    它专门嵌入了三个pragmasNoUnkeyedLiteralsDoNotCompareDoNotCopy

    最后一个 DoNotCopy 是一个大小为零的 sync.Mutex 数组。唯一的目的是让go vet 大声抱怨浅拷贝,如评论中所述:

    DoNotCopy 可以嵌入到结构中以帮助防止浅拷贝。 这不依赖于 Go 语言特性,而是一种特殊情况 在兽医检查员中。

    这一切的总结:impl.MessageState 不应该被复制,互斥锁只是为了捕捉复制。如果你这样做了,那是因为你用错了东西。

    【讨论】:

    • 如果你这样做了,那是因为你使用了错误的方式。你能扩展一下吗?复制它的缺点是什么?它会引发什么样的问题?
    • 我还想通过按值传递原型结构来了解我做错了什么。这种变化给我们项目升级到最新版本的 proto 带来了极大的不便。如果可能,我宁愿不处理 nil,而是依赖空的默认值。
    【解决方案2】:

    据我所知,Go protobuf API 包含 DoNotCopy 互斥锁有三个原因:

    1. 维护者可能希望将来更改内部表示,以一种不适用于浅拷贝的方式。
    2. 理论上,将原子和非原子访问混合到同一内存是不安全的。 protobuf 结构包含一个内部字段,通常使用原子访问进行读写。对消息调用msg.Marshal(),然后用*msg = MyMessage{...} 覆盖它会混合原子访问和非原子访问。即使这适用于今天在 x86 上的实现,也不能保证这将适用于未来的其他系统。 (见a long Go issue about this)。
    3. 如果您在消息上调用 ProtoReflect(),然后覆盖该消息,它将崩溃,因为 ProtoReflect() 结果依赖于内部反射指针 (original issue):
    d := &durationpb.Duration{Seconds: 1}
    protoreflectMessage := d.ProtoReflect()
    fmt.Printf("protoreflectMessage.Interface()=%v\n", protoreflectMessage.Interface())
    *d = durationpb.Duration{Seconds: 2}
    fmt.Printf("protoreflectMessage.Interface()=%v\n", protoreflectMessage.Interface())
    

    这会崩溃:

    protoreflectMessage.Interface()=seconds:1
    panic: invalid nil message info; this suggests memory corruption due to a race or shallow copy on the message struct
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-02-27
      • 1970-01-01
      • 2010-11-18
      • 2014-02-28
      • 2017-12-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多