Ce face sync/atomic.CompareAndSwapInt64
atomic.CompareAndSwapInt64(&n, vechi, nou) (prescurtat CAS) verifică dacă n este încă vechi și, doar în acest caz, îl face nou; totul într-un singur pas atomic. Returnează true dacă a scris. Cu el construiești operații care nu există gata făcute, de exemplu „păstrează maximul”, într-o buclă care reîncearcă.
atomic.SwapInt64(&n, nou) pune valoarea nouă și returnează valoarea de dinainte. Este util pentru „citește și resetează”, de exemplu statistici trimise o dată pe minut.
Parametri
| Parametru | Descriere |
|---|---|
addr |
Adresa variabilei. |
old |
Valoarea așteptată (doar la CAS). |
new |
Valoarea care se scrie. |
Ce returnează
CompareAndSwapInt64: true dacă a scris. SwapInt64: valoarea veche.
Exemple
Exemplul 1: Maximul calculat din mai multe goroutine
Fiecare goroutine încearcă să pună valoarea lui dacă e mai mare. Dacă alt goroutine a schimbat maximul între citire și scriere, CAS eșuează și bucla reîncearcă.
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func actualizeazaMaxim(maxim *int64, v int64) {
for {
curent := atomic.LoadInt64(maxim)
if v <= curent {
return
}
if atomic.CompareAndSwapInt64(maxim, curent, v) {
return
}
}
}
func main() {
temperaturi := []int64{18, 23, 31, 27, 12, 29, 35, 22}
var maxim int64
var wg sync.WaitGroup
for _, t := range temperaturi {
wg.Go(func() { actualizeazaMaxim(&maxim, t) })
}
wg.Wait()
fmt.Println("Temperatura maximă:", atomic.LoadInt64(&maxim), "°C")
var stare int64 = 0
fmt.Println("CAS 0->1:", atomic.CompareAndSwapInt64(&stare, 0, 1))
fmt.Println("CAS 0->2:", atomic.CompareAndSwapInt64(&stare, 0, 2), "stare =", stare)
}
Rezultat
Temperatura maximă: 35 °C
CAS 0->1: true
CAS 0->2: false stare = 1
Exemplul 2: Citește și resetează cu SwapInt64
package main
import (
"fmt"
"sync/atomic"
)
func main() {
var cereri int64
for minut := 1; minut <= 3; minut++ {
for range minut * 10 {
atomic.AddInt64(&cereri, 1)
}
deTrimis := atomic.SwapInt64(&cereri, 0)
fmt.Printf("Minutul %d: %d cereri (contor resetat la %d)\n", minut, deTrimis, atomic.LoadInt64(&cereri))
}
}
Rezultat
Minutul 1: 10 cereri (contor resetat la 0)
Minutul 2: 20 cereri (contor resetat la 0)
Minutul 3: 30 cereri (contor resetat la 0)
Greșeli frecvente
- Apelezi CAS o singură dată și ignori rezultatul
false. Dacă alt goroutine a schimbat valoarea, modificarea ta nu s-a făcut; pune CAS într-o buclă. - Faci „citește și resetează” cu
LoadInt64urmat deStoreInt64(0). Între ele se pot pierde valori; foloseșteSwapInt64.
Comenzi înrudite
sync/atomic.AddInt64: Adună (AddInt64), citește (LoadInt64) și scrie (StoreInt64) un int64 atomic, sigur între goroutine, fără mutex.sync/atomic.Int64.CompareAndSwap: Scrie valoarea nouă doar dacă valoarea curentă este cea așteptată; baza operațiilor atomice proprii, cu reîncercare.sync.Map.CompareAndSwap: Schimbă (CompareAndSwap) sau șterge (CompareAndDelete) o cheie doar dacă valoarea ei este încă cea așteptată.