Метод sync.RWMutex.RLock

Метод sync.RWMutex.RLock захватывает блокировку для чтения. Он позволяет множеству горутин одновременно читать защищенные данные, но блокирует запись до тех пор, пока все блокировки чтения не будут освобождены. В отличие от Lock, метод RLock не блокирует другие операции чтения, что делает его эффективным для сценариев с частым чтением и редкой записью.

Метод не принимает никаких параметров и не возвращает значений. После вызова RLock необходимо обязательно вызвать метод RUnlock для освобождения блокировки чтения, чтобы избежать взаимных блокировок.

Синтаксис

govar mu sync.RWMutex
mu.RLock()
// чтение защищенных данных
mu.RUnlock()

Пример

Давайте рассмотрим пример чтения данных с использованием блокировки для чтения:

gopackage main

import (
  "fmt"
  "sync"
)

func main() {
  var mu sync.RWMutex
  data := make(map[string]int)

  // Запись данных
  mu.Lock()
  data["counter"] = 42
  mu.Unlock()

  // Чтение данных
  mu.RLock()
  res := data["counter"]
  mu.RUnlock()

  fmt.Println(res)
}

Результат выполнения кода:

go42

Пример

Давайте продемонстрируем, что множество горутин могут одновременно читать данные с помощью RLock:

gopackage main

import (
  "fmt"
  "sync"
  "time"
)

func main() {
  var mu sync.RWMutex
  counter := 0
  var wg sync.WaitGroup

  reader := func(id int) {
    defer wg.Done()
    mu.RLock()
    fmt.Printf("Reader %d reads: %d\n", id, counter)
    time.Sleep(100 * time.Millisecond)
    mu.RUnlock()
  }

  for i := 0; i < 5; i++ {
    wg.Add(1)
    go reader(i)
  }

  wg.Wait()
}

Результат выполнения кода:

go"Reader 4 reads: 0"
"Reader 2 reads: 0"
"Reader 1 reads: 0"
"Reader 0 reads: 0"
"Reader 3 reads: 0"

Пример

Давайте рассмотрим ситуацию, когда операция записи ожидает освобождения блокировок чтения:

gopackage main

import (
  "fmt"
  "sync"
  "time"
)

func main() {
  var mu sync.RWMutex
  counter := 0
  var wg sync.WaitGroup

  reader := func(id int) {
    defer wg.Done()
    mu.RLock()
    fmt.Printf("Reader %d acquired read lock\n", id)
    time.Sleep(200 * time.Millisecond)
    fmt.Printf("Reader %d released read lock\n", id)
    mu.RUnlock()
  }

  writer := func() {
    defer wg.Done()
    fmt.Println("Writer waiting for write lock")
    mu.Lock()
    counter++
    fmt.Println("Writer acquired write lock")
    mu.Unlock()
  }

  for i := 0; i < 3; i++ {
    wg.Add(1)
    go reader(i)
  }

  time.Sleep(50 * time.Millisecond)
  wg.Add(1)
  go writer()

  wg.Wait()
}

Результат выполнения кода:

go"Reader 2 acquired read lock"
"Reader 1 acquired read lock"
"Reader 0 acquired read lock"
"Writer waiting for write lock"
"Reader 2 released read lock"
"Reader 1 released read lock"
"Reader 0 released read lock"
"Writer acquired write lock"

Смотрите также

  • метод sync.RWMutex.RUnlock,
    который освобождает блокировку чтения
  • метод sync.RWMutex.Lock,
    который захватывает блокировку для записи
  • метод sync.RWMutex.TryRLock,
    который пытается захватить блокировку чтения без блокировки
  • тип sync.RWMutex,
    который предоставляет механизм блокировки для чтения и записи