原子操作

简介

  1. 执行过程中不能被中断的操作。在针对某个值的操作过程中,CPU绝不会再去执行其它针对该值的操作,无论这些其他操作是否是原子操作。

  2. 对于不能被取地址的值是无法进行原子操作的。

类型

  • int32

  • int64

  • uint32

  • uint64

  • uintptr

  • unsafe.Pointer

增或减Add

//把一个int32类型的变量i32的值增大3
newi32 := atomic.AddInt32(&i32, 3)
//类似函数还有:
//AddInt64
//AddUint32
//AddUint64
//AddUintptr
//把uint32类型的变量的值增加NN(NN表示一个负整数),或者说减小-NN:
atomic.AddUint32(&uint32, ^uint32(-NN-1))
//把uint64类型的变量的值增加NN(NN表示一个负整数),或者说减小-NN:
atomic.AddUint64(&uint64, ^uint64(-NN-1))
//原因:
//一个负整数的补码可以通过对它按位(除了符号位)求反码并加一得到。
//一个负整数可以由对它的绝对值减1并求补码后得到数值的二进制表示法。
//因此表达式uint32(int32(NN))和^uint32(-NN-1)的结果都是一样的。
//比如-35都为11111111111111111111111111011101

比较并交换CAS

func CompareAndSwapInt32(addr *int32, old, new, int32) (swapped bool)
var value int32
func addValue(delta int32) {
	for  {
		v := value
		if atomic.CompareAndSwapInt32(&value, v, (v + delta)) {
			break
		}
	}
}

 

载入Load

func AddValue(delta int32) {
	for  {
    //原子地读取value的值并赋值给v。
		v := atomic.LoadInt32(&value)
    //在上面的赋值语句以及下面的if语句不会原子地执行。
    //因此加上下面的CAS是很有必要的。
		if atomic.CompareAndSwapInt32(&value, v, (v + delta)) {
			break
		}
	}
}

 

存储Store

  1. 原子地写入某个值(当前计算机中的任何CPU都不会进行其它的针对此值的读写操作)。

  2. 与CAS的区别:不关心原来的值是啥。

 

交换Swap

  1. 两个参数:被操作数的地址,新值。

  2. 与CAS区别:不关心被操作数的旧值,但是会把旧的值返回回来。

  3. 比CAS约束少,比载入功能更强。

 

原子值sync/atomic.Value

//以下程序输出是:[4 5 6]
func main() {
	var a atomic.Value
	a.Store([]int{4,5,6})
	anotherStore(a)
	fmt.Println(a.Load())
}
func anotherStore(a atomic.Value)  {
	a.Store([]int{1,2,3})
}
//以下程序输出是:[3 5 6]
func main() {
	var a atomic.Value
	a.Store([]int{4,5,6})
	anotherStore(a)
	fmt.Println(a.Load())
}
func anotherStore(a atomic.Value)  {
	b := a.Load().([]int)
	b[0] = 3
//以下程序输出是:[4 5 6]
func main() {
	var a atomic.Value
	a.Store([]int{4,5,6})
	anotherStore(a)
	fmt.Println(a.Load())
}

func anotherStore(a atomic.Value)  {
	a.Store([]int{1,2,3})
	b := a.Load().([]int)
	b[0] = 3
}

参考文献

《Go并发编程实战(第2版)》——郝林