Go并发系列:4原子操作-4.3 示例代码

87 阅读2分钟

4.3 示例代码

在本节中,我们将展示一些示例代码,通过使用 sync/atomic 包的原子操作函数来实现并发安全的操作。这些示例包括计数器的递增、标志位的设置、指针的操作等,帮助您更好地理解原子操作的应用场景和使用方法。

4.3.1 原子计数器示例

以下代码展示了如何使用 atomic.AddInt32 实现并发安全的计数器递增操作:

package main

import (
    "fmt"
    "sync"
    "sync/atomic"
)

func main() {
    var counter int32 = 0
    var wg sync.WaitGroup

    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            for j := 0; j < 1000; j++ {
                atomic.AddInt32(&counter, 1)
            }
        }()
    }

    wg.Wait()
    fmt.Printf("Final counter value: %d\n", counter)
}

在这个示例中,10 个 goroutine 并发地递增 counter,每个 goroutine 执行 1000 次递增操作。使用 atomic.AddInt32 确保了操作的原子性,最终 counter 的值应为 10000。

4.3.2 原子标志位示例

以下代码展示了如何使用 atomic.StoreInt32atomic.LoadInt32 实现并发安全的标志位设置和读取操作:

package main

import (
    "fmt"
    "sync"
    "sync/atomic"
)

func main() {
    var flag int32 = 0
    var wg sync.WaitGroup

    // Goroutine to set the flag
    wg.Add(1)
    go func() {
        defer wg.Done()
        atomic.StoreInt32(&flag, 1)
        fmt.Println("Flag set to 1")
    }()

    // Goroutine to check the flag
    wg.Add(1)
    go func() {
        defer wg.Done()
        for {
            if atomic.LoadInt32(&flag) == 1 {
                fmt.Println("Flag is 1, proceeding")
                break
            }
        }
    }()

    wg.Wait()
}

在这个示例中,第一个 goroutine 将标志位 flag 设置为 1,第二个 goroutine 通过轮询检查 flag 的值,当 flag 为 1 时,打印一条消息并退出。

4.3.3 原子指针操作示例

以下代码展示了如何使用 atomic.LoadPointeratomic.StorePointer 实现并发安全的指针操作:

package main

import (
    "fmt"
    "sync"
    "sync/atomic"
    "unsafe"
)

func main() {
    var ptr unsafe.Pointer
    var wg sync.WaitGroup

    // Goroutine to set the pointer
    wg.Add(1)
    go func() {
        defer wg.Done()
        str := "Hello, World!"
        atomic.StorePointer(&ptr, unsafe.Pointer(&str))
        fmt.Println("Pointer set to:", str)
    }()

    // Goroutine to read the pointer
    wg.Add(1)
    go func() {
        defer wg.Done()
        for {
            p := atomic.LoadPointer(&ptr)
            if p != nil {
                fmt.Println("Pointer value:", *(*string)(p))
                break
            }
        }
    }()

    wg.Wait()
}

在这个示例中,第一个 goroutine 将字符串指针 str 设置为 ptr,第二个 goroutine 通过轮询检查 ptr 的值,当 ptr 不为 nil 时,打印指针所指向的字符串并退出。

结论

通过这些示例代码,我们展示了如何使用 Go 语言的 sync/atomic 包实现并发安全的原子操作。这些示例涵盖了计数器的递增、标志位的设置和读取、以及指针的操作,展示了原子操作在实际应用中的多种场景。在并发编程中,原子操作是确保数据一致性和避免竞态条件的重要手段。在接下来的章节中,我们将继续探讨其他同步原语和并发编程技巧,帮助您更好地掌握 Go 的并发编程。