Какво е мютекс, какви типове мютекси съществуват и как да ги използваме?
sobes.tech AI
Отговор от AI
Мютексът (от английски MUTual EXclusion) е примитив за синхронизация, използван за осигуряване на изключителен достъп до споделен ресурс между конкуриращи се горутини. Той гарантира, че във всеки момент само една горутина може да притежава мютекса и да достъпва защитените данни.
В Go пакетът sync предоставя два основни типа мютекси:
-
sync.Mutex: Стандартен мютекс. Предоставя методитеLock()иUnlock(). Ако мютексът вече е блокиран, извикването наLock()блокира текущата горутина, докато не бъде освободен.Unlock()освобождава мютекса.var mu sync.Mutex var counter int func increment() { mu.Lock() // Блокира достъпа до counter counter++ mu.Unlock() // Освобождава достъпа } -
sync.RWMutex: Мютекс за четене/писане. Позволява на множество горутини да четат едновременно защитения ресурс, но само една да пише. Предоставя методитеLock(),Unlock()(за писане),RLock()иRUnlock()(за четене).var rwMu sync.RWMutex var data []int func readData() { rwMu.RLock() // Блокира за четене // Четене на data fmt.Println(data) rwMu.RUnlock() // Освобождава за четене } func writeData(val int) { rwMu.Lock() // Блокира за писане // Запис в data data = append(data, val) rwMu.Unlock() // Освобождава за писане }
Използването на мютекси е необходимо за предотвратяване на състезателни условия (race conditions), когато няколко горутини едновременно се опитват да модифицират едни и същи данни, водещи до непредсказуеми резултати.
Правила за използване:
- Извикайте
Lock()преди достъп до защитения ресурс. - Извикайте
Unlock()след приключване на достъпа. Препоръчително е да използватеdefer mu.Unlock()за гарантиране на освобождаването дори при паника. - Не се опитвайте да блокирате вече блокиран мютекс от същата горутина (може да доведе до deadlock).
- Не се опитвайте да отключите незаключен мютекс.
- При използване на
RWMutex, използвайтеRLock/RUnlockза операции за четене иLock/Unlockза операции за писане. - Мютексите не трябва да се копират след първото им използване. Предавайте ги по референция или указател.
Пример за използване на defer:
func safeIncrement() {
mu.Lock()
defer mu.Unlock() // Гарантира освобождаване
counter++
}