当我尝试在2个或更多的GoRoutine中编组Struct to XML时,我正在获得数据竞争条件。
示例主程序:http://play.golang.org/p/YhkWXWL8C0
我相信xml:"members>member"
造成这种情况。如果我把它改成正常那么一切正常。任何想法为什么go-1.4.x版本这样做。
Family struct {
XMLName xml.Name `xml:"family"`
Name string `xml:"famil_name"`
Members []Person `xml:"members>member"`
//Members []Person `xml:"members"`
}
去运行-race data_race.go给我
2015/02/06 13:53:43 Total GoRoutine Channels Created 2
2015/02/06 13:53:43 <family><famil_name></famil_name><members><person><name>ABCD</name><age>0</age></person><person><name>dummy</name><age>0</age></person></members></family>
==================
WARNING: DATA RACE
Write by goroutine 6:
runtime.slicecopy()
/usr/local/go/src/runtime/slice.go:94 +0x0
encoding/xml.(*parentStack).push()
/usr/local/go/src/encoding/xml/marshal.go:908 +0x2fb
encoding/xml.(*printer).marshalStruct()
/usr/local/go/src/encoding/xml/marshal.go:826 +0x628
encoding/xml.(*printer).marshalValue()
/usr/local/go/src/encoding/xml/marshal.go:531 +0x1499
encoding/xml.(*Encoder).Encode()
/usr/local/go/src/encoding/xml/marshal.go:153 +0xb8
encoding/xml.Marshal()
/usr/local/go/src/encoding/xml/marshal.go:72 +0xfb
main.ToXml()
/Users/kadalamittai/selfie/go/src/github.com/ivam/goal/command/data_race.go:51 +0x227
main.func·001()
/Users/kadalamittai/selfie/go/src/github.com/ivam/goal/command/data_race.go:61 +0x74
Previous read by goroutine 5:
encoding/xml.(*parentStack).trim()
/usr/local/go/src/encoding/xml/marshal.go:893 +0x2ae
encoding/xml.(*printer).marshalStruct()
/usr/local/go/src/encoding/xml/marshal.go:836 +0x203
encoding/xml.(*printer).marshalValue()
/usr/local/go/src/encoding/xml/marshal.go:531 +0x1499
encoding/xml.(*Encoder).Encode()
/usr/local/go/src/encoding/xml/marshal.go:153 +0xb8
encoding/xml.Marshal()
/usr/local/go/src/encoding/xml/marshal.go:72 +0xfb
main.ToXml()
/Users/kadalamittai/selfie/go/src/github.com/ivam/goal/command/data_race.go:51 +0x227
main.func·001()
/Users/kadalamittai/selfie/go/src/github.com/ivam/goal/command/data_race.go:61 +0x74
Goroutine 6 (running) created at:
main.AsyncExecute()
/Users/kadalamittai/selfie/go/src/github.com/ivam/goal/command/data_race.go:67 +0x15d
main.main()
/Users/kadalamittai/selfie/go/src/github.com/ivam/goal/command/data_race.go:80 +0x2bf
Goroutine 5 (finished) created at:
main.AsyncExecute()
/Users/kadalamittai/selfie/go/src/github.com/ivam/goal/command/data_race.go:67 +0x15d
main.main()
/Users/kadalamittai/selfie/go/src/github.com/ivam/goal/command/data_race.go:80 +0x2bf
==================
答案 0 :(得分:2)
这看起来像Go 1.41库中的一个错误。我已报告as a bug。希望它应该得到修复。我将在下面留下分析以供参考。
由于使用getTypeInfo()
返回结构的类型描述,因此发生了隐含的共享值。为了提高效率,它似乎是全局缓存状态。 XML编码器的其他部分采用此状态的组件并传递它。由于共享值的一个组件上有一个切片append
,似乎发生了无意的突变。
作为数据竞赛来源报告的p.stack
属性来自typeInfo
共享值的一部分,其中tinfo.parents
切片被注入{ {3}}。这最终会发生共享,并且有可能进行读写,因为稍后会在切片上发生appends
,并且可以在底层数组上进行突变。
可能应该发生的事情是切片应该是容量限制的,这样任何潜在的append
都不会对共享数组值进行写操作。
也就是说,编码器库的第897行可能会改为:
897 s.stack = parents[:split]
为:
897 s.stack = parents[:split:split]
纠正问题。