2014-12-15 8 views
5

Ich brauche eine Funktion, um float32-Werte in Go atomar hinzuzufügen. Dies ist, was mit basierend auf C-Code kam ich gefunden:Go atomic.AddFloat32()

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

es (das heißt wirklich atomar) funktionieren soll? Gibt es einen besseren/schnelleren Weg, es in Go zu machen?

Antwort

3

Suchen Sie nach Code aus der Go-Standardbibliothek, um anzupassen. Zum Beispiel von 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 
} 

für float32, die

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

Ausgang wird:

 
3.1415927 2.7182817 5.8598747 
5.8598747 5.8598747 
+0

@JimB: Wenn Sie sagen, es kann fehlschlagen, meinen Sie, dass es hängt davon ab, die Zielarchitektur? Ist der zitierte Code von go/src/sync/atomic/64bit_arm.go nur zuverlässig auf Arm? –

+0

@B_old: Entschuldigung, ich habe das Thema hier anscheinend ausreichend durcheinander gebracht. Ich stimme zu, dass das @ peterSO-Beispiel korrekt ist und den float32-Wert korrekt aktualisiert. Der Kommentar, den ich gemacht habe, war nur der Renndetektor und wie er das ungeschützte Lesen von "* addr" markieren konnte, obwohl es momentan nicht funktioniert. Sicherzustellen, dass Code unter "-race" läuft, ist oft kritisch, und wenn dies in der Zukunft angezeigt wird, ist es nicht schwer zu umgehen. (entfernte alte Kommentare, und sie waren nicht wirklich nützlich) – JimB