sync.Mutex

Golang известен своим параллелизмом (горутинами). Существует не только параллелизм, но и настоящий параллелизм, который можно реализовать с помощью Golang.
Таким образом, в этом случае мы должны убедиться, что несколько горутин не должны пытаться изменить ресурс одновременно, что приводит к конфликту.
Чтобы убедиться, что к ресурсу одновременно обращается только одна горутина, мы можем использовать нечто, называемое sync.Mutex.
Эта концепция называется взаимным исключением, а структура данных, обеспечивающая его, общепринятым названием — mutex.
Вариант использования без мьютекса
Давайте рассмотрим простой пример использования Mutex в горутинах.
Скажем, например, если нам нужно увеличить значение одной переменной одной горутиной и уменьшить значение той же переменной другой горутиной.
Этот пример предназначен только для понимания концепции.
// Execute: go run -race without_mutex.go to check whether there is Data Race or not
package main
import (
"fmt"
"sync"
"time"
)
func main() {
const loop = 100
var wg sync.WaitGroup
wg.Add(loop * 2)
// declaring a shared value
var n int = 0
for i := 0; i < loop; i++ {
go func() {
time.Sleep(time.Second / 10)
n++
wg.Done()
}()
go func() {
time.Sleep(time.Second / 10)
n--
wg.Done()
}()
}
wg.Wait()
// printing the final value of n
if n != 0 {
fmt.Println("The Final value of n should be 0. But found ", n)
return
}
fmt.Printf("\nFinal value of n is %d\n\n", n) // the final of n should be 0
}
Здесь в цикле я использовал две анонимные функции с горутинами. Одина увеличит значение n, а другая уменьшит значение n. В конце значение n должно быть 0, поскольку начальное значение равно 0, и для каждого количества циклов я увеличивал, а затем уменьшал значение, поэтому в конце оно должно быть таким же, как начальное. Но без использования Mutex это не тот случай, которого мы ожидаем.

В приведенном выше выводе мы могли видеть, что результат не является постоянным.
Мы можем определить, есть ли какая-либо гонка данных, используя -race в команде go run.
Гонка данных происходит, когда: два или более потока в одном процессе одновременно обращаются к одному и тому же месту в памяти.

sync.Mutex
Он имеет 2 метода
- Lock
- Unlock
Используйте Lock, чтобы заблокировать ресурс, чтобы только одна горутина могла получить доступ к этому ресурсу одновременно.
Unlock используется для разблокировки ресурса, который заблокирован.
Тот же вариант использования с использованием Mutex.
// Execute: go run -race main.go to check whether there is Data Race or not
package main
import (
"fmt"
"sync"
"time"
)
func main() {
const loop = 100
var wg sync.WaitGroup
wg.Add(loop * 2)
// declaring a shared value
var n int = 0
var m sync.Mutex
for i := 0; i < loop; i++ {
go func() {
time.Sleep(time.Second / 10)
m.Lock() // locking the resource n
n++
m.Unlock() // unlocking the resource n
wg.Done()
}()
go func() {
time.Sleep(time.Second / 10)
m.Lock() // locking the resource n
n--
m.Unlock() // unlocking the resource n
wg.Done()
}()
}
wg.Wait()
// printing the final value of n
if n != 0 {
fmt.Println("The Final value of n should be 0. But found ", n)
return
}
fmt.Printf("\nFinal value of n is %d\n\n", n) // the final of n should be 0
}
Здесь две горутины одновременно пытаются получить доступ к одному и тому же ресурсу (n). Но с помощью Mutex.Lock() мы можем заблокировать ресурс, чтобы его могла использовать только одна горутина (что делает потокобезопасным этот код).

В приведенном выше выводе мы могли видеть, что вывод всегда равен 0 (как мы и ожидали).
Мы также можем проверить гонку данных при использовании Mutex.

Мы могли ясно видеть, что при использовании Mutex нет гонки данных.
Также мы можем использовать оператор defer для ресурса Unlock(), чтобы он был разблокирован в конце блока, в котором он заблокирован.
