Какие примитивы синхронизации лежат в основе каналов в Go?

Ответ

В основе реализации каналов в Go лежат два основных механизма синхронизации из стандартной библиотеки и среды выполнения:

  1. Мьютекс (sync.Mutex): Для защиты от гонок данных при доступе к внутренним полям канала.
  2. Очереди ожидания и семафоры: Для блокировки и пробуждения горутин.

Внутренняя структура канала (в исходном коде runtime/chan.go она называется hchan) содержит следующие ключевые поля:

// Упрощенная структура канала
type hchan struct {
    qcount   uint           // текущее количество элементов в буфере
    dataqsiz uint           // размер буфера
    buf      unsafe.Pointer // указатель на циклический буфер

    sendx    uint           // индекс для отправки в буфер
    recvx    uint           // индекс для получения из буфера

    recvq    waitq          // очередь горутин, ожидающих получения (sudog)
    sendq    waitq          // очередь горутин, ожидающих отправки (sudog)

    lock     mutex          // мьютекс для защиты всех полей выше
}

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


  • Защита данных: Любая операция с каналом (отправка или получение) начинается с захвата lock (мьютекса). Это гарантирует, что только одна горутина в один момент времени может изменять состояние канала (его буфер, счетчики, очереди).


  • Блокировка горутины:

    • Если горутина пытается отправить данные в полный (или небуферизованный) канал, она добавляется в очередь ожидания sendq и переходит в состояние сна.
    • Если горутина пытается прочитать данные из пустого канала, она добавляется в очередь recvq и также засыпает.
  • Пробуждение горутины:

    • Когда другая горутина считывает данные из канала, она проверяет очередь sendq. Если там есть ожидающая горутина, она "пробуждается" и получает возможность завершить свою отправку.
    • Аналогично, при отправке данных в канал проверяется очередь recvq для пробуждения горутины, ожидающей на чтение.

Таким образом, канал — это не просто буфер данных, а сложная структура данных, которая инкапсулирует в себе всю логику для безопасной и эффективной синхронизации горутин.