2014-12-15 21 views
5

Ho bisogno di una funzione per aggiungere atomicamente valori float32 in Go. Questo è ciò che si avvicinò con base a un codice C che ho trovato:Vai 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 
     } 
    } 
} 

dovrebbe funzionare (cioè davvero essere atomica)? C'è un modo migliore/più veloce per farlo in Go?

risposta

3

Cercare un codice dalla libreria standard Go per adattarlo. Ad esempio, dal 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 
} 

Per float32 che diventa,

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

uscita:

 
3.1415927 2.7182817 5.8598747 
5.8598747 5.8598747 
+0

@JimB: Quando si dice che potrebbe non riuscire, vuoi dire che dipende l'architettura di destinazione? Il codice quotato di go/src/sync/atomic/64bit_arm.go è affidabile solo sul braccio? –

+0

@B_old: scusate, mi sembra di aver sufficientemente confuso l'argomento qui. Sono d'accordo che l'esempio di @ peterSO è corretto e aggiorna correttamente il valore float32. Il commento che ho fatto riguardava solo il rilevatore di gare e il modo in cui * poteva * segnalare la lettura non protetta da '* addr', anche se al momento non lo è. Garantire che il codice passi sotto '-race' è spesso fondamentale, e se questo lo segnala in futuro, non è difficile da aggirare. (rimosso vecchi commenti, e non erano veramente utili) – JimB