Go atomic.AddFloat32()

huangapple go评论71阅读模式
英文:

Go atomic.AddFloat32()

问题

我需要一个在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
        }
    }
}

这个函数能正常工作吗(即真正地原子化)?在Go语言中有更好/更快的方法吗?

英文:

I need a function to atomically add float32 values in Go.
This is what came up with based on some C code I found:

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
        }
    }
}

Should it work (i.e really be atomic)? Is there a better/faster way to do it in Go?

答案1

得分: 9

从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
}

对于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)
}

输出结果:

3.1415927 2.7182817 5.8598747
5.8598747 5.8598747
英文:

Look for some code from the Go standard library to adapt. For example, from 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
}

For float32 that becomes,

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)
}

Output:

<pre>
3.1415927 2.7182817 5.8598747
5.8598747 5.8598747
</pre>

huangapple
  • 本文由 发表于 2014年12月16日 04:14:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/27492349.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定