sync.Mutex.Lock
Метод sync.Mutex.Lock блокирует мьютекс.
Если мьютекс уже заблокирован, вызов метода блокирует выполнение текущей горутины до тех пор,
пока мьютекс не будет освобожден. После успешной блокировки,
горутина получает монопольный доступ к критической секции кода.
Метод не принимает никаких параметров и не возвращает значений.
Синтаксис
mu.Lock()
Пример базового использования
Давайте рассмотрим простой пример блокировки мьютекса для защиты общей переменной от состояния гонки:
package main
import (
"fmt"
"sync"
)
func main() {
var mu sync.Mutex
counter := 0
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
mu.Lock()
counter++
mu.Unlock()
}()
}
wg.Wait()
fmt.Println(counter)
}
Результат выполнения кода:
1000
Пример с блокировкой доступа к структуре
Рассмотрим использование мьютекса для защиты доступа к полям структуры:
package main
import (
"fmt"
"sync"
"time"
)
type SafeCounter struct {
mu sync.Mutex
value int
}
func (c *SafeCounter) Increment() {
c.mu.Lock()
c.value++
c.mu.Unlock()
}
func (c *SafeCounter) GetValue() int {
c.mu.Lock()
defer c.mu.Unlock()
return c.value
}
func main() {
counter := &SafeCounter{}
for i := 0; i < 5; i++ {
go func() {
counter.Increment()
}()
}
time.Sleep(time.Millisecond)
fmt.Println(counter.GetValue())
}
Результат выполнения кода:
5
Пример взаимной блокировки
Важно правильно использовать метод Lock, чтобы избежать взаимных блокировок.
Рассмотрим некорректный пример:
package main
import (
"fmt"
"sync"
)
func main() {
var mu1, mu2 sync.Mutex
go func() {
mu1.Lock()
mu2.Lock()
fmt.Println("Горутина 1 захватила оба мьютекса")
mu2.Unlock()
mu1.Unlock()
}()
go func() {
mu2.Lock()
mu1.Lock()
fmt.Println("Горутина 2 захватила оба мьютекса")
mu1.Unlock()
mu2.Unlock()
}()
}
Результат выполнения кода может быть взаимной блокировкой, так как горутины захватывают мьютексы в разном порядке.
"fatal error: all goroutines are asleep - deadlock!"
Пример с использованием defer
Рекомендуется использовать defer для гарантированного освобождения мьютекса:
package main
import (
"fmt"
"sync"
)
func main() {
var mu sync.Mutex
data := make(map[int]int)
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
mu.Lock()
defer mu.Unlock()
data[id] = id * id
}(i)
}
wg.Wait()
mu.Lock()
fmt.Println(data)
mu.Unlock()
}
Результат выполнения кода:
map[0:0 1:1 2:4 3:9 4:16 5:25 6:36 7:49 8:64 9:81]
Смотрите также
-
метод
sync.Mutex.Unlock,
который освобождает заблокированный мьютекс -
метод
sync.Mutex.TryLock,
который пытается заблокировать мьютекс без ожидания -
тип
sync.RWMutex,
который предоставляет более гибкие механизмы блокировки -
тип
sync.WaitGroup,
который используется для ожидания завершения группы горутин