Ce face sync/atomic.Int64.CompareAndSwap
n.CompareAndSwap(vechi, nou) face n = nou doar dacă n == vechi în acel moment și returnează true dacă a reușit. Modelul obișnuit este o buclă: citești cu Load, calculezi valoarea nouă, încerci CAS; dacă alt goroutine a schimbat valoarea între timp, CAS eșuează și reiei.
Așa poți scrie operații atomice care nu există gata făcute: scădere care nu trece sub zero, maxim, „pornește o singură dată”.
Parametri
| Parametru | Descriere |
|---|---|
old |
Valoarea pe care te aștepți să o găsești. |
new |
Valoarea de scris. |
Ce returnează
true dacă valoarea a fost schimbată.
Exemple
Exemplul 1: Locuri care nu trec sub zero
30 de clienți încearcă să rezerve din 25 de locuri; exact 25 reușesc.
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func rezerva(locuri *atomic.Int64) bool {
for {
libere := locuri.Load()
if libere == 0 {
return false
}
if locuri.CompareAndSwap(libere, libere-1) {
return true
}
}
}
func main() {
var locuri, reusite atomic.Int64
locuri.Store(25)
var wg sync.WaitGroup
for range 30 {
wg.Go(func() {
if rezerva(&locuri) {
reusite.Add(1)
}
})
}
wg.Wait()
fmt.Println("Rezervări reușite:", reusite.Load())
fmt.Println("Locuri libere:", locuri.Load())
}
Rezultat
Rezervări reușite: 25
Locuri libere: 0
Exemplul 2: Rezultatul lui CompareAndSwap
package main
import (
"fmt"
"sync/atomic"
)
func main() {
var versiune atomic.Int64
versiune.Store(7)
fmt.Println("7 -> 8:", versiune.CompareAndSwap(7, 8))
fmt.Println("7 -> 9:", versiune.CompareAndSwap(7, 9))
fmt.Println("Versiunea:", versiune.Load())
}
Rezultat
7 -> 8: true
7 -> 9: false
Versiunea: 8
Greșeli frecvente
- Recalculezi valoarea nouă în afara buclei: dacă CAS eșuează, trebuie să citești din nou și să recalculezi, altfel bucla nu se termină niciodată.
Comenzi înrudite
sync/atomic.Int64: Un int64 cu operații atomice ca metode (Add, Load, Store, Swap); varianta recomandată pentru contoare între goroutine.sync/atomic.CompareAndSwapInt64: CompareAndSwapInt64 scrie doar dacă valoarea e cea așteptată; SwapInt64 scrie și returnează valoarea veche.sync/atomic.Bool: O valoare true/false citită și scrisă atomic; bună pentru steaguri ca „închis”, „pregătit” sau „rulează deja”.