原子操作
定义:
原子操作即执行过程中不能被中断的操作。在针对某个值的原子操作执行过程中,CPU绝对不会再去执行其他针对该值的操作。
增或减
原子增/减操作即可实现被操作值的增大和减小
用于增或减的原子操作,函数名称已Add为前缀,后跟具体类型的名称:
newi32 := atomic.AddInt32(&i32,3)
第一个参数必须是指针类型,代表被操作值在内存中的存放位置,以便施加特殊CPU指令。
第二个参数与被操作值的类型相同
PS: 注意 AddUnit32
和AddUnit64
方法,因为unit类型无法为负值,无法传递一个负值来进行减小操作。
atomic.AddUint32(&ui32,^uint32(-NN-1))
原理是利用二进制补码的特性。一个负整数的补码可以通过对它按位求反码并+1得到
比较并交换
比较并交换即"Compare And Swap",简称 “CAS”。在sync/atomic包
中,已CompareAndSwap
为前缀的函数代表。
func CompareAndSwapInt32(addr *int32,old,new int32)(swaped bool)
- 第一个参数是被操作数的指针值
- 第二个参数代表原值
- 第三个参数代表新值
- 返回值代表是否交换成功
CAS操作优势是:在不创建互斥量和不形成临界区的情况下,完成并发安全的值替换操作,大大减少性能损耗。
并发情况下,old值不一定能匹配上,需要使用for循环来多次尝试。
载入
原子的读取某个值
sync/atomic
包提供了一系列函数,以Load
为前缀
atomic.LoadInt32(value &int32)(v int32)
只接受一个为函数相同类型的指针值,返回值为读取的该被操作值
存储
sync/atomic
提供了与读取相对应的存储操作函数,以Store
为前缀
atomic.StoreInt32(&i32,1)
- 第一个参数是被操作值的指针
- 第二个参数是存储的值,与被操作值同类型
交换
原子交换操作,这类函数已Swap
为前缀。
与CAS操作不同,交换操作不关心旧值,直接设置为新值,返回旧值。
atomic.SwapInt32(&int32,int32) int32
- 参数1是被操作的值的指针
- 第二个是新值
- 返回值为旧值
原子值
sync/atomic.Value
是一个结构体类型,称为 “原子值类型”,用于保存需要原子读取的值。
可接受的被操作值的类型不限。
该类型有两个指针方法Load
和Store
Store
方法有两个限制:
- 作为参数,传入方法的值不能为nil
- 作为参数传入的值,比如与之前传入的值类型相同
由于对原子值的读写操作必是原子的,同时又不接受操作值类型的限制,因此它比原子函数的适用场景大很多。有些时候,可以完美替换锁。