Golang:原子操作

前导

  • 对于一个Go程序来说,同一时刻,只有少数的goroutine真正地处于运行状态,这个数量只会与M的数量一致,而不会随着G增多而增长。
  • 为了公平起见,调度器总是会频繁地换上换下这些goroutine。中断的时机有很多,任何两条语句执行的间隙,甚至在某条语句执行的过程中都是可以的,即便这些语句在临界区内。
  • 所以,互斥锁虽然可以保证临界区代码的串行执行,但却不能保证这些代码执行的原子性
  • 能够保证原子性的,只有原子操作(atomic operation),原子操作在进行的过程中是不允许中断的,在底层,这会由CPU提供芯片级别的支持。多CPU也是如此。
  • 原子操作不可中断,所以需要足够简单快速,如果迟迟不能完成,将会极大影响计算机执行指令效率。操作系统只针对二进制位或整数的原子操作提供了支持

sync/atomic提供的原子操作

  • 加法(add)、比较并交换(compare and swap)、加载(load)、存储(store)、交换(swap)。
  • 针对int32、int64、uint32、uint64、uintptr类型,提供了上述一套函数;针对unsafe包中的Pointer,提供了除了加法之外的其余四个函数。
  • 此外,sync/atomic包还提供了一个名为Value的类型,可以被用来存储任意类型的值。

为什么参数类型中,要操作的都是指针?

  • 因为原子操作函数需要的是被操作值的指针,而不是值本身。被传入函数的参数值都会复制,基本类型的值一旦被传入函数,就已经和函数外的值毫无关系了。
  • 所以传入值本身没有任何意义(因为怎么操作也操作的是副本)。而unsafe.Pointer类型虽然是指针类型,但是要操作的实际上是指针值,而不是它指向的那个值,所以需要的仍然是指向这个指针值的指针
  • 原子操作函数拿到了被操作值的指针,就可以定位到存储该值的内存地址,然后才能够通过底层的指令,准确操作这个内存地址的数据。

原子加法操作可以做原子减法吗?

  • 可以,比如func AddInt32(addr *int32, delta int32) (new int32),将delta设置为负数即可。
  • 如果是func AddUint32(addr *uint32, delta uint32) (new uint32),需要使用^uint32(N-1),其中N是要减小的值,比如atomic.AddUint32(&a, ^uint32(10-1)),表示将a减小10。

比较并交换和交换操作有什么不同?

  • 交换指的是,把新值赋给变量,并返回变量的旧值。func SwapInt32(addr *int32, new int32) (old int32)
  • 比较并交换,是有条件的交换操作,只有在条件满足的情况下,才进行交换。func CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool)
  • 函数先判断被操作变量的当前值,是否与旧值相等,如果相等,就把新值赋给变量,并返回true表示已交换;如果不等,忽略交换操作,返回false。
  • 比较并交换是操作组合,可以实现简易自旋锁。使用场景:共享资源改变并不频繁,或者短时间内就能够达到期望。
for {
	// 直到num2的值等于10,就结束自选
	if atomic.CompareAndSwapInt32(&num2, 10, 0) {
		fmt.Println("The second number has gone to zero.")
		break
	}
	time.Sleep(time.Millisecond * 500)
}

如果写操作用的是原子操作,那么读操作还有必要用原子操作吗?

  • 很有必要,如果写操作没有进行完,读操作就来读了,就只能读到仅修改了一部分的值,显然破坏了值的完整性。
  • 一旦决定要对共享资源保护,就要做到完全保护,不完全的保护和不保护没有什么区别
  • 原子操作使用场景:只涉及并发地读写单一的整数类型,或者多个互不相关的整数类型。
  • 原子操作执行速度比互斥锁快得多,且不涉及临界区选择和死锁问题。

sync/atomic.Value

  • atomic.Value是开箱即用的,只需要声明一个该类型的变量。它只有两个指针方法,Store和Load。
  • 不能用原子值存储nil,否则会panic。
  • 向原子值存储的第一个值,决定了以后它能存储的类型。比如第一次存储了string类型,后面再存别的类型会panic。
  • 尽量不要向原子值中存储引用类型的值。
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值