Mutex
ud-206
Şimdi mutex kullanarak, old-school bir şekilde, kritik bölgeleri kitleyeceğiz. Old school diyorum çünkü Go’da aslında önerilen yöntem channel’dır.
Bunun için sync.Mutex türünü ve metotlarını kullanacağız.
Bir önceki bölümdeki denemelerimizi de yorum olarak içeren ve Mutex eklenmiş kod aşağıdaki gibi olmaktadır:
package main
import (
"fmt"
"runtime"
"sync"
// "time"
)
func main() {
fmt.Println("CPU sayısı:", runtime.NumCPU())
runtime.GOMAXPROCS(1)
//runtime.GOMAXPROCS(0), değiştirmeden olanı dönüyor
fmt.Println("Maks. aktif thread sayısı (GOMAXPROC):", runtime.GOMAXPROCS(0))
counter := 0
const gs = 10000
var wg sync.WaitGroup
//vgs adedi kadar bekle
wg.Add(gs)
var mu sync.Mutex
for i := 0; i < gs; i++ {
go func() {
mu.Lock()
v := counter
v++
//time.Sleep(time.Second)
//runtime.Gosched()
counter = v
mu.Unlock()
wg.Done()
}()
fmt.Println("Goroutine sayısı:", runtime.NumGoroutine())
}
wg.Wait()
fmt.Println("counter:", counter, "beklenen:", gs)
}
Burada var mu sync.Mutex ile bir mutex oluşturduk. Kritik bölgeyi de
mu.Lock() ve mu.Unlock() ile korumuş olduk.
Önceki yazıdaki hangi deneyi yaparsak yapalım, burada
sonuç hep doğru oluyor. Ayrıca go run -race dersek bu sefer data race
raporlanmıyor. Elbette runtime.GOMAXPROCS(1) olup olmamasına göre aktif
goroutine sayısı değişiyor ve toplam çalışma süresi değişebiliyor. Ama sonuç
her zaman doğru. Mesela 1 demek ile daha büyük değerler fark ediyor. 1
yazdığımız zaman sanıyorum main thread de bir goroutine olduğu için yaratılan
goroutine’ler çalışmaya fırsat bulamıyor ve aktif goroutine sayısı binli
sayıları buluyor. Ama 2 veya daha yüksek bir sayı verirsek 10-20 civarında
kalıyor. Bunu da bir gözlem olarak ekliyorum.
RWMutex
RWMutex isminde bir Mutex daha vardır. Bu Mutex’in amacı birden fazla reader’a izin vermektir. Böylece bir bölgede tek bir writer olduğu garanti edilir ama birden fazla reader olabilir.