去atomic.AddFloat32()

B_o*_*old 6 floating-point atomic add go

我需要一个函数来在Go中原子地添加float32值.这是基于我发现的一些C代码提出的:

package atomic

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

func AddFloat32(addr *float32, delta float32) (new float32) {
    unsafeAddr := (*uint32)(unsafe.Pointer(addr))

    for {
        oldValue := math.Float32bits(*addr)
        new       = *addr + delta
        newValue := math.Float32bits(new)

        if atomic.CompareAndSwapUint32(unsafeAddr, oldValue, newValue) {
            return
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

它应该工作(即真的是原子的)?在Go中有更好/更快的方法吗?

pet*_*rSO 6

从 Go 标准库中寻找一些代码来适应。例如,从go/src/sync/atomic/64bit_arm.go

func addUint64(val *uint64, delta uint64) (new uint64) {
    for {
        old := *val
        new = old + delta
        if CompareAndSwapUint64(val, old, new) {
            break
        }
    }
    return
}
Run Code Online (Sandbox Code Playgroud)

因为float32那变成了,

package main

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

func AddFloat32(val *float32, delta float32) (new float32) {
    for {
        old := *val
        new = old + delta
        if atomic.CompareAndSwapUint32(
            (*uint32)(unsafe.Pointer(val)),
            math.Float32bits(old),
            math.Float32bits(new),
        ) {
            break
        }
    }
    return
}

func main() {
    val, delta := float32(math.Pi), float32(math.E)
    fmt.Println(val, delta, val+delta)
    new := AddFloat32(&val, delta)
    fmt.Println(val, new)
}
Run Code Online (Sandbox Code Playgroud)

输出:

3.1415927 2.7182817 5.8598747
5.8598747 5.8598747