2014-12-15 9 views
5

Potrzebuję funkcji do atomicznego dodawania wartości float32 w Go. To właśnie wpadł na podstawie jakiegoś kodu C znalazłem: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 
     } 
    } 
} 

powinno działać (to znaczy być naprawdę atomowy)? Czy istnieje lepszy/szybszy sposób na zrobienie tego w Go?

Odpowiedz

3

Poszukaj kodu ze standardowej biblioteki Go, aby go dostosować. Na przykład, od 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 
} 

dla float32 że staje

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

wyjściowa:

 
3.1415927 2.7182817 5.8598747 
5.8598747 5.8598747 
+0

@JimB: Kiedy mówisz, może nie, masz na myśli, że to zależy od docelowa architektura? Czy cytowany kod z go/src/sync/atomic/64bit_arm.go jest niezawodny tylko na ramieniu? –

+0

@B_old: Przepraszam, wydaje mi się, że wystarczająco pomieszałem ten temat tutaj. Zgadzam się, że przykład @ peterSO jest poprawny i odpowiednio zaktualizuje wartość float32. Komentarz, który napisałem, dotyczył właśnie detektora wyścigów i tego, jak * może * oznaczać niezabezpieczony odczyt z '* addr', chociaż obecnie nie jest. Zapewnienie, że kod przechodzi przez '-race' jest często krytyczne, a jeśli oznaczy to w przyszłości, nie jest to trudne do obejścia. (usunięto stare komentarze i nie były one naprawdę użyteczne) – JimB