Go sync/atomic包Load和Store并发不安全


前言:为了保证并发安全,go语言中可以使用原子操作。其执行过程不能被中断,这也就保证了同一时刻一个线程的执行不会被其他线程中断,也保证了多线程下数据操作的一致性。

1.sync/atomic包
2.Load和Store并发不安全

1.sync/atomic包

在atomic包中对几种基础类型提供了原子操作,包括int32,int64,uint32,uint64,uintptr,unsafe.Pointer。
对于每一种类型,提供了五类原子操作分别是

  • Add, 增加和减少
  • CompareAndSwap, 比较并交换
  • Swap, 交换
  • Load , 读取
  • Store, 存储

2.Load和Store并发不安全

Load和Store操作对应与变量的原子性读写,许多变量的读写无法在一个时钟周期内完成,而此时执行可能会被调度到其他线程,无法保证并发安全。
⚠️Load 只保证读取的不是正在写入的值,Store只保证写入是原子操作。
所以在使用的时候要注意。
下面简单示例:

package main

import (
    "sync"
    "sync/atomic"
    "fmt"
)

var (
    wg  sync.WaitGroup
    mu  sync.Mutex
    num int32
)

func wrap(callback func()) {
    wg.Add(1)
    go func() {
        callback()
        wg.Done()
    }()
}

// go build -race
func main() {
    // 1099 、892, 并发不安全
    //wrap(incNumAtomic)
    //wrap(incNumAtomic)

    // 1200, 并发安全
    wrap(incNumAtomic2)
    wrap(incNumAtomic2)

    wg.Wait()
    fmt.Printf("num=%d\n", num)
}

func incNumAtomic() {
    for i := 0; i < 600; i++ {
        // atomic.Load*系列函数只能保证读取的不是正在写入的值(比如只被修改了一半的数据)
        // 同样的atomic.Store* 只保证写入是原子操作(保证写入操作的完整性)
        val := atomic.LoadInt32(&num)
        atomic.StoreInt32(&num, val+1)
    }
}

func incNumAtomic2() {
    for i := 0; i < 600; i++ {
        atomic.AddInt32(&num, 1)
    }
}

总结

点击查看源码,哈哈哈...

Github Demo

你可能感兴趣的:(Go sync/atomic包Load和Store并发不安全)