原子操作
Go语言运行时调度系统会恰当安排所有goroutine的运行,在同一时刻,只可能有少数goroutine处于运行状态,并且这个数量只会与M的数量一致,而不会睡着G的增多而增多
_
为了公平起见,Golang调度器会频繁的换上或换下这些goroutine
- 换上: 将goroutine由非运行状态转换为运行状态,并促使其中其中的代码在某个GPU上运行
- 换下: 使一个goroutine中的代码中断执行,并让它的运行状态转换为非运行状态
原子操作有哪些?
sync/atomic包中函数可以做的原子操作有:加法(add)、比较并交换(cas)、加载(load)、存储(store)和交换(cap)
- 原子操作函数需要的是被操作值的指针,而不是值本身
- 原子加法操作函数可以做原子减法操作
sync/atomic.Value
- atomic.Value 属于结构体类型,结构体类型属于值类型
- 不能使用原子值存贮nil
- 向原子值存储的第一个值,决定它以后能且只能存储哪一个类型的值
- 如果有可能的话最好将原子值存储到结构体中,这样可以通过验证类型以防存储的原子操作因为类型报错
- 尽量不要向原子值存储引用类型的值 (如切片、字典、通道是引用类型的值),造成安全漏洞
package mainimport ("fmt""reflect""os""sync/atomic""errors""io")func main() {demo()}func demo() {// Demo 1fmt.Println("Demo 1")var box atomic.Valuefmt.Println("Copy box to box2")box2 := boxv1 := [...]int{1,2,3}fmt.Printf("Store %v to box.\n", v1)box.Store(v1)fmt.Printf("The value load from box is %v.\n", box.Load())fmt.Printf("The value load from box2 is %v.\n", box2.Load())fmt.Println()// Demo 2v2 := "123"fmt.Printf("Store %q to box2.\n", v2)box2.Store(v2)fmt.Printf("The value load from box is %v.\n", box.Load())fmt.Printf("The value load from box2 is %v.\n", box2.Load())fmt.Println()// Demo 3fmt.Println("Copy box to box3.")box3 := boxfmt.Printf("The value load from box3 is %v.\n", box3.Load())v3 := 123fmt.Printf("Store %d to box2.\n", v3)// box3.Store(v3)_ = box3fmt.Println()// Demo4var box4 atomic.Valuev4 := errors.New("something wrong")fmt.Printf("Store an error with message %q to box4.\n", v4)box4.Store(v4)v41 := io.EOFfmt.Println("Store a value of the same type to box4.")box4.Store(v41)v42, ok := interface{}(&os.PathError{}).(error)if ok {fmt.Printf("Store a value of type %T that implements error interface to box4.\n", v42)// box4.Store(v42)}fmt.Println()// Demo5fmt.Println("Demo5")box5, err := NewAtomicValue(v4)if err != nil {fmt.Printf("error: %s\n", err)}fmt.Printf("The legal type n box5 is %s.\n", box5.TypeOfValue())fmt.Println("Store a value of the same type to box5.")err = box5.Store(v41) // 将原子值存储到结构体中,自定义存储操作if err != nil {fmt.Printf("error: %s\n", err)}fmt.Printf("Store a value of type %T that implemetns error interface to box5.\n", v42)err = box5.Store(v42)if err != nil {fmt.Printf("errors: %s\n", err)}fmt.Println()// Demo6fmt.Println("Demo6")var box6 atomic.Valuev6 := []int{1,2,3}fmt.Printf("Store %v to box6.\n", v6)box6.Store(v6)v6[1] = 4 // 造成安全漏洞fmt.Printf("The value load from box6 is %v.\n", box6.Load())v6 = []int{1,2,3}store := func(v []int) {replica := make([]int, len(v))copy(replica, v)box6.Store(replica)}fmt.Printf("Store %v to box6.\n", v6)store(v6)v6[2] = 5fmt.Printf("The value load from box6 is %v.\n", box6.Load())}type atomicValue struct {v atomic.Valuet reflect.Type}func NewAtomicValue(example interface{}) (*atomicValue, error){if example == nil {return nil, errors.New("atomic value: nil example")}return &atomicValue{t: reflect.TypeOf(example),}, nil}func (av *atomicValue) Store(v interface{}) error {if v == nil {return errors.New("atomic value: nil value")}t := reflect.TypeOf(v)if t != av.t {return fmt.Errorf("atomic value: wrong type: %s", t)}av.v.Store(v)return nil}func (av *atomicValue) Load() interface{} {return av.v.Load()}func (av *atomicValue) TypeOfValue() reflect.Type {return av.t}
