Что такое операция CAS (Compare-And-Swap) и для чего она используется в Go?

Ответ

CAS (Compare-And-Swap) — это атомарная инструкция, выполняемая на уровне процессора, которая позволяет реализовать безопасные конкурентные изменения данных без использования блокировок (мьютексов).

Как это работает:

Операция принимает три аргумента:

  1. Указатель на значение в памяти (addr).
  2. Ожидаемое старое значение (old).
  3. Новое значение (new).

Процессор атомарно (непрерываемо) выполняет следующее:

  • Сравнивает текущее значение по адресу addr с old.
  • Если они равны, то записывает по адресу addr значение new и возвращает true.
  • Если они не равны (значит, другой поток уже изменил данные), операция ничего не меняет и возвращает false.

Пример в Go (пакет sync/atomic):

import (
    "fmt"
    "sync/atomic"
)

func main() {
    var counter int64 = 0

    // Попытка увеличить счетчик с 0 до 1.
    // &counter - адрес переменной
    // 0 - ожидаемое старое значение
    // 1 - новое значение
    swapped := atomic.CompareAndSwapInt64(&counter, 0, 1)

    fmt.Printf("Операция успешна: %v, новое значение: %dn", swapped, counter)
    // Вывод: Операция успешна: true, новое значение: 1

    // Повторная попытка с тем же старым значением (0) провалится,
    // так как текущее значение уже 1.
    swapped = atomic.CompareAndSwapInt64(&counter, 0, 2)
    fmt.Printf("Операция успешна: %v, новое значение: %dn", swapped, counter)
    // Вывод: Операция успешна: false, новое значение: 1
}

Преимущества и использование:

  • Производительность: CAS позволяет создавать "lock-free" алгоритмы, которые могут быть значительно быстрее мьютексов в условиях высокой конкуренции, так как не блокируют потоки.
  • Реализация конкурентных структур: На основе CAS строятся многие высокоуровневые примитивы синхронизации и структуры данных, например, lock-free очереди, стеки и даже некоторые части реализации каналов в Go.