01

介绍

我们已经介绍过 Mutex、RWMutex 等并发原语操作,如果您还没有阅读,请查看文末「推荐阅读」列表。

本文我们介绍 sync/atomic 包提供的原子操作的方法,相比并发原语操作,使用原子操作会更轻量。

我们知道,相同代码在不同 CPU 架构中编译的结果可能不同,sync/atomic 包提供的原子操作的方法帮我们解决了这个问题,所以如果您想保证原子操作,一定要使用 sync/atomic 包提供的原子操作的方法。

02

方法

因为 Go (1.15)目前还没有支持泛型,所以每个 sync/atomic 包提供的原子操作的方法,都包含不同类型的同名方法。但是不同类型的同名方法除了类型不同,使用方法是相同的。

细心的读者可能发现,为什么 Add 方法只支持 5 种类型,其它方法都支持 6 种类型,因为在 Go 语言中,指针是不能运算的,Add 方法是修改操作,其它方法否是存取操作。限于篇幅,我们重点介绍 Add 方法。

Add 方法:

Add 方法的功能就是给参数 1 的地址中的值,加上参数 2 的 delta 的值。如果类型是有符号类型,参数 2 可以是负值,用于原子减法运算;如果类型是无符号类型,参数 2 不可以是负值,此时分两种情况:

  • 情况 1 是参数 2 是一个无符号类型的变量 v,-v 在 GO 语言中是合法的。
  • 情况 2 是参数 2 是一个正整数常量 c,-c 在 Go 语言中是非法的,此时我们可以使用 ^T(c-1) 作为参数 2 的值。

如果 ^T(c-1) 中的 c 是一个类型确定的值,可以简化为 ^(c-1)。

示例代码:

如果您感兴趣的话,可以将示例代码中第 10 行代码替换为 counter++,运行程序并查看运行结果是否会有不同。

Swap 方法:

Swap 方法的功能是原值替换为新值,并返回原值。

CompareAndSwap 方法:

CompareAndSwap 方法的功能是比较原值,符合条件则将原值替换为新值。

Load 方法:

Load 方法的功能是取值。

Store 方法:

Store 方法的功能是存值。

03

value 类型

细心的读者可能已经发现,上述 5 种方法,都是针对特定类型的方法。sync/atomic 还有一个 value 类型,它有两个方法,分别是 Load 和 Store,用于读取和存储任意类型的值,它没有 Add 和 Swap。

Load 方法的返回结果类型和 Store 方法的参数类型都是空接口类型 interface{},所以 Store 方法的参数可以接收任意类型的值。

需要注意的是,*Value 类型的 v,只要调用过一次 Store 方法,那么传入此方法的后续参数类型必须和之前传入参数的类型一致,否则会导致 panic。

04

总结

本文主要介绍了 sync/atomic 包的原子操作的方法的基本使用,其中重点介绍了 Add 方法和 Value 类型的方法,读者朋友可以根据实际场景选用最合适的方法。