Как реализовать потокобезопасный связанный список в Go?

Ответ

Для реализации потокобезопасного (thread-safe) связанного списка в Go необходимо защитить все операции чтения и записи с помощью примитивов синхронизации, таких как sync.Mutex или sync.RWMutex.

Самый простой и надежный подход — использовать блокировку на уровне всей структуры (coarse-grained locking). Это означает, что любая операция блокирует весь список.

Пример с sync.RWMutex:

RWMutex предпочтительнее, если предполагается, что операций чтения будет значительно больше, чем операций записи. Он позволяет множеству горутин одновременно читать список.

import "sync"

// Node - узел списка
type Node struct {
    Value int
    Next  *Node
}

// SafeLinkedList - потокобезопасный связанный список
type SafeLinkedList struct {
    head *Node
    mu   sync.RWMutex // Используем RWMutex для оптимизации чтений
}

// Insert добавляет элемент в начало списка (операция записи)
func (s *SafeLinkedList) Insert(value int) {
    s.mu.Lock() // Эксклюзивная блокировка для записи
    defer s.mu.Unlock()

    newNode := &Node{Value: value, Next: s.head}
    s.head = newNode
}

// Search ищет элемент в списке (операция чтения)
func (s *SafeLinkedList) Search(value int) bool {
    s.mu.RLock() // Блокировка на чтение
    defer s.mu.RUnlock()

    current := s.head
    for current != nil {
        if current.Value == value {
            return true
        }
        current = current.Next
    }
    return false
}

Ключевые моменты:

  1. Тип блокировки: Используйте s.mu.Lock() / s.mu.Unlock() для операций, изменяющих структуру списка (добавление, удаление), и s.mu.RLock() / s.mu.RUnlock() для операций только для чтения (поиск, подсчет длины).
  2. Длительность блокировки: Блокировка должна удерживаться на протяжении всей операции. Например, при поиске мьютекс блокируется перед началом обхода и разблокируется после его завершения. Попытка блокировать и разблокировать каждый узел отдельно (fine-grained locking) значительно сложнее в реализации и чревата ошибками (race conditions, deadlocks).