Czym jest mutex, jakie rodzaje mutexów istnieją i jak ich używać?
sobes.tech AI
Odpowiedź od AI
Mutex (od ang. MUTual EXclusion) to prymityw synchronizacji używany do zapewnienia wyłącznego dostępu do współdzielonego zasobu między konkurującymi gorutynami. Gwarantuje, że w każdym momencie tylko jedna gorutyna może posiadać mutex i odwoływać się do chronionych danych.
W Go pakiet sync zapewnia dwa główne typy mutexów:
-
sync.Mutex: Standardowy mutex. Udostępnia metodyLock()iUnlock(). Jeśli mutex jest już zablokowany, wywołanieLock()blokuje bieżącą gorutynę do czasu odblokowania.Unlock()odblokowuje mutex.var mu sync.Mutex var counter int func increment() { mu.Lock() // Blokuje dostęp do counter counter++ mu.Unlock() // Odblokowuje dostęp } -
sync.RWMutex: Mutex do odczytu/zapisu. Pozwala wielu gorutynom jednocześnie odczytywać chroniony zasób, ale tylko jednej pisać. Udostępnia metodyLock(),Unlock()(do zapisu),RLock()iRUnlock()(do odczytu).var rwMu sync.RWMutex var data []int func readData() { rwMu.RLock() // Blokuje do odczytu // Odczyt danych fmt.Println(data) rwMu.RUnlock() // Odblokowuje odczyt } func writeData(val int) { rwMu.Lock() // Blokuje do zapisu // Zapis do danych data = append(data, val) rwMu.Unlock() // Odblokowuje zapis }
Użycie mutexów jest konieczne do zapobiegania warunkom wyścigu (race conditions), gdy wiele gorutyn próbuje jednocześnie modyfikować te same dane, co prowadzi do nieprzewidywalnych rezultatów.
Zasady użycia:
- Wywołać
Lock()przed dostępem do chronionego zasobu. - Wywołać
Unlock()po zakończeniu dostępu. Zaleca się użyciedefer mu.Unlock()dla gwarancji odblokowania nawet w przypadku paniki. - Nie próbować blokować już zablokowanego mutexu z tej samej gorutyny (może prowadzić do deadlocka).
- Nie próbować odblokować niezablokowanego mutexu.
- Przy użyciu
RWMutex, używaćRLock/RUnlockdo operacji odczytu iLock/Unlockdo operacji zapisu. - Mutexy nie powinny być kopiowane po pierwszym użyciu. Przekazuj je przez referencję lub wskaźnik.
Przykład użycia defer:
func safeIncrement() {
mu.Lock()
defer mu.Unlock() // Gwarantuje odblokowanie
counter++
}