Тип atomic.Bool
Тип atomic.Bool представляет собой атомарное логическое значение.
В отличие от обычного bool, atomic.Bool гарантирует,
что операции чтения и записи будут выполняться атомарно,
что особенно важно при работе с несколькими горутинами.
Основные методы типа: Load для чтения значения,
Store для записи значения,
Swap для обмена значения с возвратом предыдущего,
CompareAndSwap для сравнения и замены значения.
Синтаксис
Для использования atomic.Bool нужно объявить переменную
этого типа и использовать ее методы:
var flag atomic.Bool
flag.Store(true)
value := flag.Load()
old := flag.Swap(false)
success := flag.CompareAndSwap(true, false)
Метод Load
Метод Load атомарно возвращает текущее значение
логического флага:
package main
import (
"fmt"
"sync/atomic"
)
func main() {
var flag atomic.Bool
flag.Store(true)
res := flag.Load()
fmt.Println(res)
}
Результат выполнения кода:
true
Метод Store
Метод Store атомарно устанавливает новое значение
логического флага:
package main
import (
"fmt"
"sync/atomic"
)
func main() {
var flag atomic.Bool
flag.Store(true)
flag.Store(false)
res := flag.Load()
fmt.Println(res)
}
Результат выполнения кода:
false
Метод Swap
Метод Swap атомарно заменяет значение на новое
и возвращает предыдущее значение:
package main
import (
"fmt"
"sync/atomic"
)
func main() {
var flag atomic.Bool
flag.Store(true)
oldValue := flag.Swap(false)
fmt.Println(oldValue)
newValue := flag.Load()
fmt.Println(newValue)
}
Результат выполнения кода:
true
false
Метод CompareAndSwap
Метод CompareAndSwap сравнивает текущее значение
с ожидаемым и, если они равны, заменяет его на новое.
Возвращает true, если замена выполнена успешно:
package main
import (
"fmt"
"sync/atomic"
)
func main() {
var flag atomic.Bool
flag.Store(true)
success := flag.CompareAndSwap(true, false)
fmt.Println(success)
current := flag.Load()
fmt.Println(current)
}
Результат выполнения кода:
true
false
А теперь пример, когда сравнение не проходит:
package main
import (
"fmt"
"sync/atomic"
)
func main() {
var flag atomic.Bool
flag.Store(true)
success := flag.CompareAndSwap(false, true)
fmt.Println(success)
current := flag.Load()
fmt.Println(current)
}
Результат выполнения кода:
false
true
Использование в горутинах
Давайте рассмотрим пример безопасного использования
atomic.Bool в конкурентной среде:
package main
import (
"fmt"
"sync"
"sync/atomic"
"time"
)
func main() {
var flag atomic.Bool
var wg sync.WaitGroup
flag.Store(false)
for i := 0; i < 10; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
if flag.CompareAndSwap(false, true) {
fmt.Printf("Горутина %d захватила флаг\n", id)
time.Sleep(100 * time.Millisecond)
flag.Store(false)
} else {
fmt.Printf("Горутина %d не смогла захватить флаг\n", id)
}
}(i)
}
wg.Wait()
}
Возможный результат выполнения кода:
"Горутина 9 захватила флаг"
"Горутина 0 не смогла захватить флаг"
"Горутина 1 не смогла захватить флаг"
"Горутина 2 не смогла захватить флаг"
"Горутина 3 не смогла захватить флаг"
"Горутина 4 не смогла захватить флаг"
"Горутина 5 не смогла захватить флаг"
"Горутина 6 не смогла захватить флаг"
"Горутина 7 не смогла захватить флаг"
"Горутина 8 не смогла захватить флаг"
Смотрите также
-
тип
atomic.Int32,
который предоставляет атомарный 32-битный целочисленный тип -
тип
atomic.Int64,
который предоставляет атомарный 64-битный целочисленный тип -
тип
atomic.Uint32,
который предоставляет атомарный беззнаковый 32-битный целочисленный тип -
тип
atomic.Uint64,
который предоставляет атомарный беззнаковый 64-битный целочисленный тип