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.