登录
首页 >  Golang >  Go问答

为什么Go生成的protobuf文件使用同步锁?

来源:stackoverflow

时间:2024-03-09 21:00:26 459浏览 收藏

本篇文章向大家介绍《为什么Go生成的protobuf文件使用同步锁?》,主要包括,具有一定的参考价值,需要的朋友可以参考一下。

问题内容

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

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

state.world.script.HandleEvent 的调用复制锁定值:throne/server/messages.PlayerDialogeStatus 包含 google.golang.org/protobuf/internal/impl.MessageState 包含sync.Mutex 复制锁

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

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

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


解决方案


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

它专门嵌入了三个 pragmasnounkeyedliteralsdonotcomparedonotcopy

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

donotcopy 可以嵌入到结构中以帮助防止浅复制。 这不依赖于 go 语言特性,而是一种特殊情况 在兽医检查器内。

总而言之:impl.messagestate 不应该被复制,互斥体只是为了捕获复制。如果你这样做,那是因为你使用了错误的方式。

据我所知,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

文中关于的知识介绍,希望对你的学习有所帮助!若是受益匪浅,那就动动鼠标收藏这篇《为什么Go生成的protobuf文件使用同步锁?》文章吧,也可关注golang学习网公众号了解相关技术文章。

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>