Мьютекс (mutex, mutual exclusion) — это примитив синхронизации, который обеспечивает эксклюзивный доступ к общим ресурсам в многопоточной среде.
Базовый мьютекс с двумя методами:
Lock()
- захватывает мьютекс (блокирует, если уже захвачен)Unlock()
- освобождает мьютексvar mu sync.Mutex
var sharedData int
func increment() {
mu.Lock()
defer mu.Unlock() // Важно использовать defer для гарантированного освобождения
sharedData++
}
Оптимизирован для сценариев с частым чтением и редкой записью:
Lock()
/Unlock()
- для записи (эксклюзивный доступ)RLock()
/RUnlock()
- для чтения (множественный доступ)var rwMu sync.RWMutex
var cache map[string]string
func get(key string) string {
rwMu.RLock()
defer rwMu.RUnlock()
return cache[key]
}
func set(key, value string) {
rwMu.Lock()
defer rwMu.Unlock()
cache[key] = value
}
defer
)// Плохо:
mu.Lock()
// что-то пошло не так...
return // мьютекс остался заблокированным
mu.Unlock()
// Хорошо:
mu.Lock()
defer mu.Unlock()
var mu sync.Mutex
func a() {
mu.Lock()
defer mu.Unlock()
b() // вызов функции, которая тоже пытается захватить мьютекс
}
func b() {
mu.Lock()
defer mu.Unlock()
// ...
}
// Небезопасно:
if len(slice) > 0 {
mu.Lock()
v := slice[0] // Гонка данных - slice мог измениться
mu.Unlock()
}
// Безопасно:
mu.Lock()
defer mu.Unlock()
if len(slice) > 0 {
v := slice[0]
}
if mu.TryLock() {
defer mu.Unlock()
// Критическая секция
} else {
// Альтернативная логика
}
type SafeCounter struct {
sync.Mutex
count int
}
func (c *SafeCounter) Increment() {
c.Lock()
defer c.Unlock()
c.count++
}
type ProtectedData struct {
mu sync.RWMutex
items map[int]string
}
func (p *ProtectedData) Get(id int) string {
p.mu.RLock()
defer p.mu.RUnlock()
return p.items[id]
}
// Сравнение производительности
BenchmarkMutex-8 100000000 10.2 ns/op
BenchmarkRWMutex-8 200000000 7.5 ns/op (для чтения)
BenchmarkAtomic-8 500000000 3.1 ns/op
Мьютексы — фундаментальный инструмент для безопасной работы с общими данными в Go, но требуют аккуратного использования.