将两个值存储在一个变量中。

huangapple go评论128阅读模式
英文:

Store 2 values in one variable

问题

这是Go代码正确且可移植的吗?我需要将两个计数器(每次调用只更新一个计数器)存储在一个变量中,以避免在实际代码中使用单个atomic.AddUint64()时锁定整个结构体。

  1. package main
  2. import "fmt"
  3. var long uint64 // 实际计数器存储
  4. func main() {
  5. left := uint32(100) // 第一个计数器
  6. right := uint32(200) // 第二个计数器
  7. long = uint64(left)
  8. long = long << 32 | uint64(right)
  9. fmt.Println(left, right)
  10. long += uint64(1 << 32) // 增加左计数器
  11. long += 1 // 增加右计数器
  12. xLeft := uint32(long >> 32) // 获取左计数器
  13. xRight := uint32(long) // 获取右计数器
  14. fmt.Println(xLeft, xRight)
  15. }

你可以在这里查看代码:http://play.golang.org/p/aBlp-Zatgn

英文:

Is this Go code correct and portable, I need to store 2 counters (each call only one counter will be updated) in one variable to avoid locks in actual code where I am going to use single atomic.AddUint64() instead of locking whole struct.

<!-- language: lang-golang -->

  1. package main
  2. import &quot;fmt&quot;
  3. var long uint64 // Actual counters storage
  4. func main() {
  5. left := uint32(100) // First counter
  6. right := uint32(200) // Second counter
  7. long = uint64(left)
  8. long = long &lt;&lt; 32 | uint64(right)
  9. fmt.Println(left, right)
  10. long += uint64(1 &lt;&lt; 32) // Increment left
  11. long += 1 // Increment right
  12. xLeft := uint32(long &gt;&gt; 32) // Get left
  13. xRight := uint32(long) // Get right
  14. fmt.Println(xLeft, xRight)
  15. }

http://play.golang.org/p/aBlp-Zatgn

答案1

得分: 0

这段Go代码是正确的,只要你使用64位宽度的无符号整数。

在这种情况下,通过sync/atomic包提供了对Go编译器支持的体系结构的可移植性。然而,请注意,并非所有体系结构都支持对64位宽度数据进行“真正”的原子操作。例如,i386实现使用了CAS循环:

  1. TEXT ·AddUint64(SB),NOSPLIT,$0-20
  2. // 没有XADDQ,所以使用CMPXCHG8B循环
  3. MOVL addr+0(FP), BP
  4. TESTL $7, BP
  5. JZ 2(PC)
  6. MOVL 0, AX // crash with nil ptr deref
  7. // DI:SI = delta
  8. MOVL delta_lo+4(FP), SI
  9. MOVL delta_hi+8(FP), DI
  10. // DX:AX = *addr
  11. MOVL 0(BP), AX
  12. MOVL 4(BP), DX
  13. addloop:
  14. // CX:BX = DX:AX (*addr) + DI:SI (delta)
  15. MOVL AX, BX
  16. MOVL DX, CX
  17. ADDL SI, BX
  18. ADCL DI, CX
  19. // if *addr == DX:AX {
  20. // *addr = CX:BX
  21. // } else {
  22. // DX:AX = *addr
  23. // }
  24. // all in one instruction
  25. LOCK
  26. CMPXCHG8B 0(BP)
  27. JNZ addloop
  28. // success
  29. // return CX:BX
  30. MOVL BX, new_lo+12(FP)
  31. MOVL CX, new_hi+16(FP)
  32. RET

这可能会引发一个问题:为什么不使用带有锁的结构体?

编辑以回答评论中的问题:是的,使用32位整数将在所有Go支持的体系结构上实现实际的原子操作,因为据我所知,它们都支持XADDL(或类似操作)。

英文:

> Is this Go code correct and portable

It is correct, as long as you work with unsigned integers of 64-bit width.

Portability in this case is provided by the sync/atomic packages to the architectures supported by the Go compiler. Note, however, that not all architectures support "true" atomic operations on 64-bit wide data. For example, the i386 implementation uses a CAS-loop:

  1. TEXT &#183;AddUint64(SB),NOSPLIT,$0-20
  2. // no XADDQ so use CMPXCHG8B loop
  3. MOVL addr+0(FP), BP
  4. TESTL $7, BP
  5. JZ 2(PC)
  6. MOVL 0, AX // crash with nil ptr deref
  7. // DI:SI = delta
  8. MOVL delta_lo+4(FP), SI
  9. MOVL delta_hi+8(FP), DI
  10. // DX:AX = *addr
  11. MOVL 0(BP), AX
  12. MOVL 4(BP), DX
  13. addloop:
  14. // CX:BX = DX:AX (*addr) + DI:SI (delta)
  15. MOVL AX, BX
  16. MOVL DX, CX
  17. ADDL SI, BX
  18. ADCL DI, CX
  19. // if *addr == DX:AX {
  20. // *addr = CX:BX
  21. // } else {
  22. // DX:AX = *addr
  23. // }
  24. // all in one instruction
  25. LOCK
  26. CMPXCHG8B 0(BP)
  27. JNZ addloop
  28. // success
  29. // return CX:BX
  30. MOVL BX, new_lo+12(FP)
  31. MOVL CX, new_hi+16(FP)
  32. RET

That may open the question: why not use a struct with a lock?


Edit to answer question in comments: Yes, using a 32-bit integer would result in actual atomic operations on all Go-supported architectures because they all support XADDL (or analog) to the best of my knowledge.

huangapple
  • 本文由 发表于 2015年5月22日 15:48:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/30391141.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定