Ce face sync/atomic.Pointer
atomic.Pointer[T] este un tip generic: atomic.Pointer[Config] ține un *Config. Valoarea zero este un pointer nil. Store(p) publică un obiect nou, Load() returnează pointerul curent, Swap îl înlocuiește și îl dă pe cel vechi, iar CompareAndSwap înlocuiește doar dacă pointerul curent este cel așteptat.
Modelul obișnuit este „copiază, modifică, publică”: cititorii fac Load() și lucrează cu un obiect care nu se mai schimbă, iar cine actualizează construiește un obiect nou și îl publică cu Store. Față de atomic.Value nu ai nevoie de conversii și nu există panici din cauza tipului.
Ce returnează
Load: *T (poate fi nil). Swap: pointerul vechi. CompareAndSwap: bool.
Exemple
Exemplul 1: Curs valutar actualizat din mers
package main
import (
"fmt"
"sync"
"sync/atomic"
)
type Curs struct {
EUR, USD float64
}
func main() {
var curs atomic.Pointer[Curs]
fmt.Println("Înainte de Store:", curs.Load())
curs.Store(&Curs{EUR: 4.97, USD: 4.58})
var wg sync.WaitGroup
sume := make([]float64, 3)
for i, eur := range []float64{10, 25, 100} {
wg.Go(func() {
c := curs.Load() // obiectul nu se mai schimbă după publicare
sume[i] = eur * c.EUR
})
}
wg.Wait()
fmt.Printf("În lei: %.2f\n", sume)
vechi := curs.Swap(&Curs{EUR: 4.98, USD: 4.61})
fmt.Println("Vechi:", *vechi, "nou:", *curs.Load())
}
Rezultat
Înainte de Store: <nil>
În lei: [49.70 124.25 497.00]
Vechi: {4.97 4.58} nou: {4.98 4.61}
Exemplul 2: Actualizare cu CompareAndSwap
Copiem obiectul curent, îl modificăm și îl publicăm doar dacă nu l-a înlocuit altcineva între timp.
package main
import (
"fmt"
"sync"
"sync/atomic"
)
type Lista struct {
Nume []string
}
func adauga(p *atomic.Pointer[Lista], nume string) {
for {
vechi := p.Load()
nou := &Lista{Nume: append(append([]string{}, vechi.Nume...), nume)}
if p.CompareAndSwap(vechi, nou) {
return
}
}
}
func main() {
var invitati atomic.Pointer[Lista]
invitati.Store(&Lista{})
var wg sync.WaitGroup
for _, n := range []string{"Ana", "Bogdan", "Carmen", "Dan"} {
wg.Go(func() { adauga(&invitati, n) })
}
wg.Wait()
fmt.Println("Invitați:", len(invitati.Load().Nume))
}
Rezultat
Invitați: 4
Greșeli frecvente
- Modifici obiectul după ce l-ai publicat cu
Store(curs.Load().EUR = 5). Alte goroutine îl citesc în același timp: cursă de date. Creează un obiect nou. - Folosești rezultatul lui
Load()fără să verificinilînainte de primulStore.
Comenzi înrudite
sync/atomic.Value: Ține o valoare de orice tip, înlocuită și citită atomic; folosită pentru configurări schimbate „din mers”.sync.RWMutex: Lacăt pentru citire și scriere: mai mulți cititori pot lucra deodată (RLock), dar un scriitor lucrează singur (Lock).sync/atomic.Int64: Un int64 cu operații atomice ca metode (Add, Load, Store, Swap); varianta recomandată pentru contoare între goroutine.