【Go】atomic原子操作

点击阅读更多查看文章内容


简介

在 Go 语言中,atomic 包提供了一系列的原子操作函数,用于在并发环境中安全地操作共享变量。原子操作是不可分割的操作,即在执行过程中不会被其他 goroutine 打断,从而避免了数据竞争(Data Race)和并发问题。atomic 包是 Go 标准库的一部分,常用于实现高性能的并发控制。

原子操作的核心概念

  1. 原子性
    • 原子操作是不可分割的,要么全部执行成功,要么全部不执行。且在执行过程中,不会被其他 goroutine 打断。
  2. 无锁编程
    • 原子操作通常基于硬件指令(如 CAS, Compare-And-Swap)实现,无需使用锁(如 sync.Mutex)。
  3. 适用场景
    • 原子操作适用于简单的共享变量操作(如计数器、标志位等)。对于复杂的共享资源操作,仍然需要使用锁或其他同步机制。

atomic 包的主要功能

atomic 包提供了对以下类型的原子操作支持:

  • int32
  • int64
  • uint32
  • uint64
  • uintptr
  • unsafe.Pointer

以下是 atomic 包中常用的函数:

  1. 加载(Load)

    • 原子地读取变量的值。

    • 示例:

      1
      value := atomic.LoadInt32(&counter)
  2. 存储(Store)

    • 原子地设置变量的值。

    • 示例:

      1
      atomic.StoreInt32(&counter, 10)
  3. 增加(Add)

    • 原子地增加变量的值。

    • 示例:

      1
      atomic.AddInt32(&counter, 1)
  4. 比较并交换(Compare-And-Swap, CAS)

    • 如果变量的值等于预期值,则设置为新值。

    • 示例:

      1
      swapped := atomic.CompareAndSwapInt32(&counter, 10, 20)
  5. 交换(Swap)

    • 原子地设置变量的值,并返回旧值。

    • 示例:

      1
      oldValue := atomic.SwapInt32(&counter, 20)

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func main() {
var n int32
var wg sync.WaitGroup
wg.Add(1000)
for i := 0; i < 1000; i++ {
go func() {
atomic.AddInt32(&n, 1)
wg.Done()
}()
}
wg.Wait()

fmt.Println(atomic.LoadInt32(&n)) // 1000
}

以上代码n能正确的返回1000,但如果不使用原子操作,使用n++的话由于并发执行线程不安全结果无法正确返回

作者

ShiHaonan

发布于

2025-03-20

更新于

2025-03-20

许可协议

评论