Sobes.tech
Middle

Šta je mutex, koje vrste mutexa postoje i kako ih koristiti?

sobes.tech АИ

Одговор од АИ

Мьютекс (од англ. 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), кога повеќе горутини истовремено се обидуваат да модифицираат исти податоци, што може да доведе до непредвидливи резултати.

Правила за користење:

  1. Повикај Lock() пред пристапот до заштитениот ресурс.
  2. Повикај Unlock() по завршувањето на пристапот. Препорачливо е да се користи defer mu.Unlock() за гарантирање на отклучувањето дури и во случај на паника.
  3. Не се обидувај да заклучиш веќе заклучен мьютекс од истата горутиња (може да доведе до дедлок).
  4. Не се обидувај да отклучиш незаклучен мьютекс.
  5. Кога се користи RWMutex, користи RLock/RUnlock за операции на читање и Lock/Unlock за операции на запишување.
  6. Мьютексите не треба да се копираат по првото користење. Тие треба да се пренесуваат по референца или покажувач.

Пример за користење defer:

func safeIncrement() {
    mu.Lock()
    defer mu.Unlock() // Гарантира отклучување
    counter++
}