sync/atomic.Int64.And în Go

Aplică atomic un ȘI (And) sau un SAU (Or) pe biți; folosit pentru steaguri (flags) partajate între goroutine.

Sintaxă
func (x *Int64) And(mask int64) (old int64)
func (x *Int64) Or(mask int64) (old int64)

Ce face sync/atomic.Int64.And

Un număr întreg poate ține mai multe steaguri da/nu, câte unul pe fiecare bit. n.Or(masca) aprinde biții din mască (n |= masca), iar n.And(^masca) îi stinge (n &= ^masca). Ambele se fac atomic și returnează valoarea dinainte de modificare.

Pentru că primești valoarea veche, afli dacă tu ai fost cel care a aprins un bit: vechi & masca == 0. Metodele există și pentru Int32, Uint32, Uint64, Uintptr și ca funcții (atomic.OrInt64, atomic.AndInt64).

Parametri

Parametru Descriere
mask Masca de biți: pentru Or, biții de aprins; pentru And, biții de păstrat.

Ce returnează

Valoarea veche (de dinainte de operație).

Exemple

Exemplul 1: Permisiuni ca steaguri pe biți

package main

import (
	"fmt"
	"sync/atomic"
)

const (
	Citire  int64 = 1 << iota // 1
	Scriere                   // 2
	Stergere                  // 4
)

func main() {
	var drepturi atomic.Int64

	vechi := drepturi.Or(Citire | Scriere)
	fmt.Printf("Or:  vechi=%03b nou=%03b\n", vechi, drepturi.Load())

	vechi = drepturi.Or(Stergere)
	fmt.Printf("Or:  vechi=%03b nou=%03b\n", vechi, drepturi.Load())

	vechi = drepturi.And(^Scriere) // stinge bitul de scriere
	fmt.Printf("And: vechi=%03b nou=%03b\n", vechi, drepturi.Load())

	fmt.Println("Poate scrie:", drepturi.Load()&Scriere != 0)
	fmt.Println("Poate șterge:", drepturi.Load()&Stergere != 0)
}

Rezultat

Or:  vechi=000 nou=011
Or:  vechi=011 nou=111
And: vechi=111 nou=101
Poate scrie: false
Poate șterge: true

Exemplul 2: Etape bifate de mai mulți lucrători

Fiecare lucrător aprinde bitul etapei lui. Din valoarea veche, exact un lucrător află că el a bifat ultima etapă și trimite notificarea.

package main

import (
	"fmt"
	"sync"
	"sync/atomic"
)

func main() {
	etape := []string{"plată", "stoc", "factură", "livrare"}
	toate := int64(1)<<len(etape) - 1
	var gata atomic.Int64
	var notificari atomic.Int32

	var wg sync.WaitGroup
	for i := range etape {
		wg.Go(func() {
			vechi := gata.Or(1 << i)
			if vechi|1<<i == toate { // eu am bifat ultima etapă
				notificari.Add(1)
			}
		})
	}
	wg.Wait()
	fmt.Printf("Etape terminate: %04b\n", gata.Load())
	fmt.Println("Comanda completă:", gata.Load() == toate)
	fmt.Println("Notificări „comandă gata” trimise:", notificari.Load())
}

Rezultat

Etape terminate: 1111
Comanda completă: true
Notificări „comandă gata” trimise: 1

Greșeli frecvente

  • Scrii n.And(masca) când vrei să stingi biții din mască. And păstrează doar biții din mască; pentru stingere dai masca negată: n.And(^masca).
  • Folosești valoarea returnată ca valoare nouă. And și Or returnează valoarea veche; pentru cea nouă apelează Load().

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.Bool: O valoare true/false citită și scrisă atomic; bună pentru steaguri ca „închis”, „pregătit” sau „rulează deja”.