Skip to content

Instantly share code, notes, and snippets.

@lesismal
Created December 13, 2023 14:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lesismal/3673322106d032abc10a2a06ee138f9b to your computer and use it in GitHub Desktop.
Save lesismal/3673322106d032abc10a2a06ee138f9b to your computer and use it in GitHub Desktop.
cpu cache一致性、volatile、编译器优化
package main
func main() {
flag := true
// 协程 A
go func() {
println("Goroutine start\n")
for flag {
println("Goroutine flag:", flag)
// time.Sleep(time.Second * 1)
continue
}
println("Goroutine finish\n")
}()
for i := 0; true; i++ {
flag = false
continue
}
}
@lesismal
Copy link
Author

go tool compile -S test.go
go tool objdump test.o
TEXT main.main(SB) gofile..E:/test/test.go
  test.go:3             0x10a9                  493b6610                CMPQ SP, 0x10(R14)
  test.go:3             0x10ad                  765c                    JBE 0x110b
  test.go:3             0x10af                  55                      PUSHQ BP
  test.go:3             0x10b0                  4889e5                  MOVQ SP, BP
  test.go:3             0x10b3                  4883ec18                SUBQ $0x18, SP
  test.go:4             0x10b7                  488d0500000000          LEAQ 0(IP), AX          [3:7]R_PCREL:type:bool
  test.go:4             0x10be                  e800000000              CALL 0x10c3             [1:5]R_CALL:runtime.newobject<1>
  test.go:4             0x10c3                  4889442410              MOVQ AX, 0x10(SP)
  test.go:4             0x10c8                  c60001                  MOVB $0x1, 0(AX)
  test.go:7             0x10cb                  488d0500000000          LEAQ 0(IP), AX          [3:7]R_PCREL:type:noalg.struct { F uintptr; X0 *bool }
  test.go:7             0x10d2                  e800000000              CALL 0x10d7             [1:5]R_CALL:runtime.newobject<1>
  test.go:7             0x10d7                  488d0d00000000          LEAQ 0(IP), CX          [3:7]R_PCREL:main.main.func1
  test.go:7             0x10de                  488908                  MOVQ CX, 0(AX)
  test.go:7             0x10e1                  833d0000000000          CMPL 0(IP), $0x0        [2:6]R_PCREL:runtime.writeBarrier+-1
  test.go:7             0x10e8                  90                      NOPL
  test.go:7             0x10e9                  7507                    JNE 0x10f2
  test.go:7             0x10eb                  488b4c2410              MOVQ 0x10(SP), CX
  test.go:7             0x10f0                  eb0d                    JMP 0x10ff
  test.go:7             0x10f2                  e800000000              CALL 0x10f7             [1:5]R_CALL:runtime.gcWriteBarrier1
  test.go:7             0x10f7                  488b4c2410              MOVQ 0x10(SP), CX
  test.go:7             0x10fc                  49890b                  MOVQ CX, 0(R11)
  test.go:7             0x10ff                  48894808                MOVQ CX, 0x8(AX)
  test.go:7             0x1103                  e800000000              CALL 0x1108             [1:5]R_CALL:runtime.newproc<1>
  test.go:17            0x1108                  90                      NOPL
  test.go:1             0x1109                  ebfd                    JMP 0x1108
  test.go:3             0x110b                  e800000000              CALL 0x1110             [1:5]R_CALL:runtime.morestack_noctxt
  test.go:3             0x1110                  eb97                    JMP main.main(SB)

TEXT main.main.func1(SB) gofile..E:/test/test.go
  test.go:7             0x1112                  493b6610                CMPQ SP, 0x10(R14)
  test.go:7             0x1116                  0f8690000000            JBE 0x11ac
  test.go:7             0x111c                  55                      PUSHQ BP
  test.go:7             0x111d                  4889e5                  MOVQ SP, BP
  test.go:7             0x1120                  4883ec18                SUBQ $0x18, SP
  test.go:7             0x1124                  488b4208                MOVQ 0x8(DX), AX
  test.go:7             0x1128                  4889442410              MOVQ AX, 0x10(SP)
  test.go:8             0x112d                  0f1f440000              NOPL 0(AX)(AX*1)
  test.go:8             0x1132                  e800000000              CALL 0x1137             [1:5]R_CALL:runtime.printlock<1>
  test.go:8             0x1137                  488d0500000000          LEAQ 0(IP), AX          [3:7]R_PCREL:go:string."Goroutine start\n\n"
  test.go:8             0x113e                  bb11000000              MOVL $0x11, BX
  test.go:8             0x1143                  e800000000              CALL 0x1148             [1:5]R_CALL:runtime.printstring<1>
  test.go:8             0x1148                  e800000000              CALL 0x114d             [1:5]R_CALL:runtime.printunlock<1>
  test.go:9             0x114d                  eb32                    JMP 0x1181
  test.go:9             0x114f                  0f1f00                  NOPL 0(AX)
  test.go:10            0x1152                  e800000000              CALL 0x1157             [1:5]R_CALL:runtime.printlock<1>
  test.go:10            0x1157                  488d0500000000          LEAQ 0(IP), AX          [3:7]R_PCREL:go:string."Goroutine flag: "
  test.go:10            0x115e                  bb10000000              MOVL $0x10, BX
  test.go:10            0x1163                  e800000000              CALL 0x1168             [1:5]R_CALL:runtime.printstring<1>
  test.go:10            0x1168                  488b442410              MOVQ 0x10(SP), AX
  test.go:10            0x116d                  0fb608                  MOVZX 0(AX), CX
  test.go:10            0x1170                  89c8                    MOVL CX, AX
  test.go:10            0x1172                  e800000000              CALL 0x1177             [1:5]R_CALL:runtime.printbool<1>
  test.go:10            0x1177                  e800000000              CALL 0x117c             [1:5]R_CALL:runtime.printnl<1>
  test.go:10            0x117c                  e800000000              CALL 0x1181             [1:5]R_CALL:runtime.printunlock<1>
  test.go:9             0x1181                  488b442410              MOVQ 0x10(SP), AX
  test.go:9             0x1186                  803800                  CMPB 0(AX), $0x0
  test.go:9             0x1189                  75c7                    JNE 0x1152
  test.go:14            0x118b                  e800000000              CALL 0x1190             [1:5]R_CALL:runtime.printlock<1>
  test.go:14            0x1190                  488d0500000000          LEAQ 0(IP), AX          [3:7]R_PCREL:go:string."Goroutine finish\n\n"
  test.go:14            0x1197                  bb12000000              MOVL $0x12, BX
  test.go:14            0x119c                  e800000000              CALL 0x11a1             [1:5]R_CALL:runtime.printstring<1>
  test.go:14            0x11a1                  e800000000              CALL 0x11a6             [1:5]R_CALL:runtime.printunlock<1>
  test.go:15            0x11a6                  4883c418                ADDQ $0x18, SP
  test.go:15            0x11aa                  5d                      POPQ BP
  test.go:15            0x11ab                  c3                      RET
  test.go:7             0x11ac                  e800000000              CALL 0x11b1             [1:5]R_CALL:runtime.morestack
  test.go:7             0x11b1                  90                      NOPL
  test.go:7             0x11b2                  e95bffffff              JMP main.main.func1(SB)

@lesismal
Copy link
Author

https://www.v2ex.com/t/999936#reply97

看了下汇编,for 循环里不断设置 flag 的语句这块生成的汇编只有一条 NOPL (空指令)汇编、应该是被编译器优化掉了。
随便在 for 循环里加个 print 之类的,都可以让 flag=false 生效。

OP 的疑问其实是 CPU 指令自己的事情,并不算是编程语言相关的,所以我再提一下这个帖子,建议 OP 先看下:
https://www.51cto.com/article/716546.html
还有例如这个帖子:
https://xiaolincoding.com/os/1_hardware/cpu_mesi.html#mesi-%E5%8D%8F%E8%AE%AE

CPU 多核缓存一致性由 CPU 保证。一些人举例子的 i++是属于多个并发各自执行一组指令时各组指令自己的原子性问题、和 cache 一致性其实应该是无关的。

很多认为的可见性的不一致问题,应该是编译器优化导致的,例如:
#96
c++ const 变量通过指针强改内容但其他用到 const 变量的地方仍然是旧值、因为编译器认为常量直接类似宏替换了,需要 volatile 指定每次读内存主要也是为了告诉编译器不要优化这里的内容

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment