GUI (Grafiksel Kullanıcı Arayüzü)
Mutex ile Asenkron İşlem Sırası
Size konu başlığını şöyle açıklayayım. Örneğin bir banka uygulaması para çekme ve yatırma gibi özelliklere sahiptir. Programlama mantığında para yatırmak ve çekmek için mevcut para miktarını bilmemiz gerekir. Banka uygulamasının mantığı en basit derecede bu şekilde çalışır.
Banka hesabımızda asenkron işlem yapıldığını varsayalım. Yani bir hesaptan aynı anda birden fazla kullanıcı işlem yapıyor olsun.
Örneğin hesabımızda 100₺ olsun. Birinci kullanıcı 20₺ yatırsın. Aynı anda ikinci kullanıcı 50₺ çeksin. Bu iki kullanıcınında kullandığı program işlem yapmaya başladığında önce para miktarını alıyor. Daha sonra yapılacak işleme göre ya ekleme ya da çıkarma işlemi yapıyor. Fakat birden fazla kullanıcı aynı anda bu işlemi yaparsa hesaptaki parada yanlışlık olacaktır.
Basit bir görsel ile inceleyelim.
İşlemlere aynı anda başlandığını varsayalım.
Örnek asenkron işlem
Bu işlemin sonuncunda hangi kullancının işlemi sonuncu olarak biterse para miktarı onun sonucu olur. Yani kullanıcı 2'nin işlemi kullanıcı 1'den sonra biterse yeni para miktarı 50₺ olur.
Bu gibi örneklerde asenkron işlemlere sıra verilmesi gerekir. Mutex tam olarak bu işi yapıyor. Bunun için bir Mutex nesnesi oluşturuyoruz. İşlemlerimizi bu nesne üzerinden yapıyoruz. Bu nesne aynı anda sadece bir işlemi gerçekleştiriyor. Bu yüzden sıra işlemi sağlıyor. Önce başlayan asenkron işlem ilk sırada oluyor. Tamamlanınca diğerine sıra geçiyor. Böyle düşündüğümüz zaman "bunun senkron programlamadan ne farkı var?" diyebilirsiniz. Farkı asenkron fonksiyonların içindeki istediğimiz kısımları senkron çalıştırmamız.
Örnek bir para yatırma-çekme uygulaması yazalım. İşlemin sağlık çalışması için, para miktarıyla aynı anda sadece bir kişi işlem yapabilmelidir.
1
package main
2
3
import (
4
"fmt"
5
"sync" // mutex'i kullanmak için
6
)
7
//global olarak mutex nesnesi oluşturalım.
8
var mt sync.Mutex
9
10
11
func paraÇek(bakiye *float64, çekilecekMiktar float64, wg *sync.WaitGroup) {
12
/*
13
* mt isimli mutex'i bu işlem yapılırken kilitliyoruz.
14
* bu sayede mt mutex'ini başka işlemler kullanamıyor.
15
*/
16
mt.Lock()
17
18
/*
19
bu kısımda asenkron olmasını istemediğimiz işlemi yapalım.
20
*/
21
*bakiye -= 15
22
fmt.Printf("Yeni Bakiye: %.2f\n", *bakiye)
23
24
/*
25
* diğer işlemlerinde kullanabilmesi için mutex'i tekrardan açalım.
26
* mt mutex açılınca diğer asenkron işlemdeki mt mutex'i çalışmaya başlar.
27
*/
28
mt.Unlock()
29
fmt.Println("Çekme işlemi tamamlandı.")
30
31
/*
32
* waitgroup ile işlemin tamamlandığını belirttik.
33
* böylece wg havuzu 2'den 1'e düştü
34
*/
35
wg.Done()
36
}
37
38
//bu fonksiyonda yukarıdaki ile aynı mantıkta
39
func paraYatır(bakiye *float64, yatırılacakMiktar float64, wg *sync.WaitGroup) {
40
mt.Lock()
41
*bakiye += 65
42
fmt.Printf("Yeni Bakiye: %.2f\n", *bakiye)
43
mt.Unlock()
44
fmt.Println("Yatırma işlemi tamamlandı.")
45
wg.Done()
46
}
47
48
func main() {
49
50
/*
51
* asenkron işlemlerimizin, ana iş parçacığında tamamlanmasını
52
* beklemek için waitgroup nesnesi oluşturalım
53
*/
54
var wg sync.WaitGroup
55
56
//2 fonksiyonu da bekleyeceğimiz için Add'e 2 yazalım
57
wg.Add(2)
58
59
//fonksiyonlarımızın kullancağı bakiye değişkenimiz
60
var bakiye float64 = 100
61
fmt.Printf("İlk Bakiye: %.2f\n", bakiye)
62
63
/*
64
* paraÇek ve paraYatır fonksiyonlarımızı aynı anda başlatıyoruz.
65
* hangisi daha önce başlarsa mutex sırasına ilk o girer. bu esnada diğer
66
* fonksiyon mutex'in açılmasını bekler.
67
*/
68
go paraÇek(&bakiye, 25, &wg)
69
go paraYatır(&bakiye, 65, &wg)
70
71
/*
72
* ana iş parçacığı tamamlandığında asenkron çalışan fonksiyonları beklemez.
73
* beklemediğinde de asenkron fonksiyonlar çalışmadan program sonlanır.
74
* ana iş parçacığının asenkron işlemleri beklemesi için waitgroup sonucunun 0 olmasını bekleriz.
75
* wg.Add(2) yazarak 2 adet wg.Done() fonksiyonu çalıştığında wg.Add(0) olur ve
76
* wg.Wait() tamamlanır ve program başka işlemler yapılmıyor ise sonlanır.
77
*/
78
wg.Wait()
79
}
Copied!
Çıktımız aşağıdaki gibi olacaktır.
İlk Bakiye: 100.00 Yeni Bakiye: 165.00 Yatırma işlemi tamamlandı. Yeni Bakiye: 150.00 Çekme işlemi tamamlandı.
Yukarıdaki çıktıya göre, paraYatır() fonksiyonu paraÇek() fonkisyonundan önce çalışmıştır.
Last modified 1yr ago
Copy link