Concurrent Programming in Golang: Understanding Mutex

MuharremCandan
3 min readFeb 4, 2024

--

Golang, eşzamanlı (concurrent) programlamaya odaklanan bir dil olarak bilinir. Ancak, go routinlerdeki (goroutines) değişkenler arasında paylaşımın düzgün bir şekilde kontrol edilmesi önemlidir. Bu makalede, sync paketinin Mutex yapısını kullanarak race condition'ların nasıl ele alınacağını anlayacağız.

Race Condition Nedir?

Race condition, birden fazla go rutini aynı değişkeni değiştirmeye çalıştığında ortaya çıkan durumdur. Bu durum, beklenmeyen sonuçlara, hatalara ve uygulama kararsızlığına yol açabilir. Şöyle ki aynı anda hem veriyi değiştirdiğinizi hem de okumaya çalıştığınız düşünün?

Örnek:

Kod üzerinden gidecek olursak eğer, n değişkeni üzerinde işlem yapan 2 adet goroutinlerimiz mevcut. Bir tanesi değeri güncelliyor iken bir tanesi ise değerin durmuna göre bir çıktı veriyor. Verilmiş olan n değerine göre çıktının sonucunu hepimiz “Çift : 10” olacak şekilde bekleriz. Ama işler biraz farklı ilerliyor…

package main

import (
"fmt"
"time"
)

func CiftMi(n int) bool {
return n%2 == 0
}

func main() {

n := 10

go func() {
is_even := CiftMi(n)
time.Sleep(5 * time.Millisecond)
if is_even {
fmt.Printf("Çift: %d", n)
} else {
fmt.Printf("Tek : %d", n)
}
}()

go func() {
n++
}()

time.Sleep(time.Second)
}

Bunun sebebi tam olarak şu yüzden kaynaklanıyor. Siz bir değişken tanımlıyorsunuz ve o değişken 10 değerini atıyorsunuz. Sonrasında satır satır kodum çalışsın bana çıktı versin diyorsunuz. Ama Concurrent programlamada işlemi devreye alıp bir sonraki işlemi de götürüyor yanında. Bu sebeple ilk goroutin değer kontrolünü 10 üzerinden yapıyor ama bu sırada 2. goroutin değeri arttırmış oluyor ve 1. goroutin ekrana değeri basana kadar değer değişmiş oluyor ve ekrana basarkenki okudğu değer 11 olmuş oluyor. Bu sebeple tutarsız, yanlış sonuç veren bir kod elde etmiş oluyoruz. Peki bu durumun çözümü ne?

ChatGPT ne yapıyorsun karşim ?

Mutex Kullanımı

Mutex (Mutex = Mutual Exclusion), bir anda sadece bir go rutininin belirli bir kod bloğuna erişmesine izin veren bir kilit mekanizmasıdır. İşte bir örnek:

package main

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

func CiftMi(n int) bool {
return n%2 == 0
}

func main() {

n := 10
var m sync.Mutex

go func() {
m.Lock()
defer m.Unlock()
is_even := CiftMi(n)
time.Sleep(5 * time.Millisecond)
if is_even {
fmt.Printf("Çift: %d", n)
} else {
fmt.Printf("Tek : %d", n)
}
}()

go func() {
m.Lock()
n++
m.Unlock()
}()

time.Sleep(time.Second)
}

Bu örnekte, sync.Mutex kullanarak counter değişkenini koruduk. Lock ve Unlock yöntemleri arasındaki kritik bölge, aynı anda sadece bir go rutini tarafından erişilebilir.

Sonuç

Golang’da Mutex kullanarak, eşzamanlı programlamanın getirdiği riskleri minimize edebilir ve uygulamalarınızın daha güvenilir olmasını sağlayabiliriz. Bu mekanizmaları doğru bir şekilde kullanmak, race condition’ları önlemenin ve kodunuzu daha güvenli hale getirmenin önemli bir adımıdır.

Sosyal Medya ve Bağlantılar:

--

--

MuharremCandan
MuharremCandan

Written by MuharremCandan

Hayalleri hayatının kaptanlığını yapan, limandan daha taptaze yazılım serüvenine yelken açan bir gemide Miço.

No responses yet