简介
-
执行过程中不能被中断的操作。在针对某个值的操作过程中,CPU绝不会再去执行其它针对该值的操作,无论这些其他操作是否是原子操作。
-
对于不能被取地址的值是无法进行原子操作的。
类型
-
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
-
原子地写入某个值(当前计算机中的任何CPU都不会进行其它的针对此值的读写操作)。
-
与CAS的区别:不关心原来的值是啥。
交换Swap
-
两个参数:被操作数的地址,新值。
-
与CAS区别:不关心被操作数的旧值,但是会把旧的值返回回来。
-
比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版)》——郝林