2 回答
TA贡献1876条经验 获得超5个赞
在第一种情况下,错误是由原子更新的字段没有正确对齐引起的。
在 ARM 和 x86-32 上,调用者负责安排以原子方式访问的 64 位字的 64 位对齐。全局变量或分配的结构体或切片中的第一个字可以依赖于 64 位对齐。
TA贡献1775条经验 获得超11个赞
如果您偶然发现此错误,这里有一些解决问题的技巧:
如 OP 中所述,最简单的方法是将所有 64 位原子值放在结构的顶部:
c := struct {
val int64 // pos 0
val2 int64 // pos 8
valid bool // pos 16
}{val2: 1}
fmt.Println(atomic.AddInt64(&c.val2, 1))
如果您出于某种原因不想将此字段放在顶部,则始终可以_ [4]byte在 64 位字段上方放置 a以确保正确填充它。
c := struct {
val int64 // pos 0
valid bool // pos 8
_ [4]byte // pos 9; compiler adds additional [3]byte at pos 13 for alignment
val2 int64 // pos 16, correctly aligned
}{val2: 1}
fmt.Println(atomic.AddInt64(&c.val2, 1)) // => 2
请注意,如果字段已经对齐,这将不起作用;相反,如果它之前没有恐慌,它现在就会恐慌。
c := struct {
val int64 // pos 0
_ [4]byte // pos 8; compiler adds no padding
val2 int64 // pos 12, not a multiple of 8!
}{val2: 1}
fmt.Println(atomic.AddInt64(&c.val2, 1)) // => runtime error: invalid memory address [...]
您还可以依赖 64 位元素切片中的第一个元素将正确对齐的行为:
c := struct {
val int64
valid bool
val2 []int64
}{val2: []int64{1}}
fmt.Println(atomic.AddInt64(&c.val2[0], 1))
请注意,这不适用于数组,因为它们的值直接存储在结构中,而不是像切片数据那样存储在堆中。
您可以使用的最后一个技巧是将结构中的字段声明为指向int64;的指针。如果int64它指向的是对齐的,那么它会顺利运行。
c := struct {
val int64
valid bool
val2 *int64
}{val2: new(int64)}
fmt.Println(atomic.AddInt64(c.val2, 1))
如果你不想弄脏你的手sync/atomic,请记住,这sync.Mutex是一个比处理原子更清晰、更容易理解的解决方案。
- 2 回答
- 0 关注
- 304 浏览
添加回答
举报