如下代码,可能会panic嘛?
package main
import (
"fmt"
"time"
)
const (
FIRST = "WHAT THE"
SECOND = "F*CK"
)
func main() {
var s string
go func() {
i := 1
for {
i = 1 - i
if i == 0 {
s = FIRST
} else {
s = SECOND
}
time.Sleep(10)
}
}()
for {
if s == "WHAT" {
panic(s)
}
fmt.Println(s)
time.Sleep(10)
}
}
多次运行后,是会出现panic的,为什么会这样?我们先看下string的内部结构:
struct {
str uintptr
len int
}
看个例子:
package main
import(
"fmt"
"unsafe"
)
func main() {
var str string = "hello world"
p := (*struct {
str uintptr
len int
})(unsafe.Pointer(&str))
fmt.Printf("%+v\n", p) // &{str:5057758 len:11}
}
简单解释一下原因:
对于这样一个 struct ,go 无法保证原子性地完成赋值,因此可能会出现goroutine 1 刚修改完指针(str)、还没来得及修改长度(len),goroutine 2 就读取了这个string 的情况。
因此我们看到了 “WHAT” 这个输出 —— 这就是将 s 从 “F*CK” 改成 “WHAT THE” 时,str 改了、len 还没来得及改的情况(仍然等于4)。对于这样一个 struct ,golang 无法保证原子性地完成赋值,因此可能会出现goroutine 1 刚修改完指针(str)、还没来得及修改长度(len),goroutine 2 就读取了这个string 的情况。