" Umut, hiç görmeyen birine gökkuşağını anlatmak kadar zor ve imkansız... "

Categories

-

Vb.Net MultiThreading Kullanimi !

MultiThreading bilgisayar biliminde, bir programin kendini es zamanli birden fazla is parçasina ayirabilmesinin bir yoludur. Multithreading çalisma kabaca bir programda ayni anda birden fazla islem yapabilme yetenegi olarak tanimlanabilir. Bilgisayarda yapilan tüm islemler geçici bellek dedigimiz RAM’de tutuldugundan, bir programi çalistirip RAM’e yüklendigi andan itibaren ki haline de "Proses(Islem)" ismini vermekteyiz. 

Bilgisayarin bir islemi (prosesi) çalistirmasini yarayan birimine CPU(Mikro Islemci) diyoruz. Mikroislemci (CPU), herhangi bir x aninda sade ve sadece bir adet prosesi çalistirabilir. Iste CPU’larin bu çalisma biçimine Single Processing(Tek Islemli Çalisma) denilmektedir. (Ek bilgi olarak; CPU’yu bu sekilde kullanarak çalisan isletim sistemlerine ise Single Processing(Tek Islemli) Isletim Sistemi denilmektedir.)  

MultiThreading ve islem arasindaki fark bir isletim sisteminden digerine degismekle birlikte genel olarak threading olusumu ve kaynaklari paylasmasi açisindan islemden'den ayrilir.Çoklu thread'ler paralel olarak pek çok bilgisayar sisteminde uygulanabilir. Tek islemci kullanildigi durumlarda  MultiThreading' li uygulama zaman dilimleme ile gerçeklestirilir; tek islemci fakli threading' ler arasinda çok hizli geçis yapar ve bu durumda islemler gerçekte olmasa bile es zamanli kosuluyormus izlenimi verir. Çok islemcili sistemlerde farkli threading' ler farkli islemciler üzerinde es zamanli olarak çalisabilir.Günümüzde tek islemli CPU’lar yerlerini Multi Processing(Çok Islemli Çalisma) yahut Multi Tasking(Çok Görevli Çalisma) CPU’lara birakmistir.

Yukaridaki ekran görüntüsüne bakarsaniz eger ayni anda(x aninda) birden fazla process çalismaktadir. Iste bunu yapabilen Multi Processing yahut Multi Tasking özelliklerdir.

Birden fazla processin ayni anda çalisiyormus gibi gözükmesinin nedeni isletim sistemine ait özel bir mekanizmanin özelligidir. Bu mekanizma, processleri belirli araliklarla(milisaniye) periyodik olarak çalistirmaktadir ve bu yönteme Zaman Paylasimli Çalisma denilmektedir.

Bu mekanizma sayesinde birden fazla process CPU tarafindan belirli bir süre ile sirali olarak çalistirilmaktadir. Çalisma süresi her sistem için farklilik gösteren bu süreye Quanta Süresi denmektedir.(Örn; Win32 sistemleri için quanta süresi 20 milisaniyedir.)

Yukaridaki paragrafta birden fazla process CPU tarafindan belirli bir süre ile sirali olarak çalistirilmaktadir, demistik. Iste sirasi gelen processin çalismasinada "Prosessin Çizelgeye Girmesi" denmektedir.

Isletim sistemleri processleri sirali olarka çalistirabilmek adina Döngüsel Çizelgeleme isimli bir algoritma kullanir. Döngüsel Çizelgeleme ile bir processin durdurulup siradaki processin çalistirilmasi ise "Görevler Arasi Geçis(Task Switch)" olarak adlandirilir.

Sirali bir sekilde çalistirilacak processlerin önceligi bu mekanizmada önemlidir. Örnegin, Wind32 sistemleri processleri 0 – 31 araliginda farkli öncelik düzeyine göre siniflandirmaktadir. Eger ki farkli öncelik düzeylerine sahip prosesler bir arada çalismak zorunda kalirlarsa, çalisma sekli ve algoritmasi farkli olacak, döngüsel çizelgeleme degil Öncelikli Döngüsel Çizelgeleme algoritmasi kullanilacaktir.

Pek çok modern isletim sistemi bir is düzenleyicisi yardimiyla hem zaman dilimleme hem de çok islemcili thread' lemeyi desteklemektedir. Isletim sistem çekirdegi (kernel) sistem çagrilari vasitasi ile programciya thread' leri kontrol etme imkâni saglamaktadir. Bunun yoklugunda programlar, zamanlayicilar, sinyaller veya diger yöntemleri kullanarak kendi çalismalarini sonlandirabilirler. Bunlara user-space thread' ler denir.

Bizde yazdigimiz programlarda ayni anda birden fazla islem yaptirmak istiyorsak Threadleri kullanabiliriz. Farkli threadler ayni fonksiyonu kullanabilecegi gibi her thread farkli bir is yapan ayri fonksiyonlarida kullanabilir. Threadleri kullanarak basit bir uygulama yazalim.

Dim thread1 As New Thread(New ThreadStart(ProgressBar1Doldur))
Dim thread2 As New Thread(New ThreadStart(ProgressBar2Doldur))
Dim thread3 As New Thread(New ThreadStart(ProgressBar3Doldur))

thread1.Start()
thread2.Start()
thread3.Start()

Yukaridaki kodda gördügünüz gibi ilk olarak yeni bir thread olusturuyor ve bu threadin kullanacagi fonksiyonu da ThreadStart nesnesi içinde yaziyoruz. thread1.Start() dedigimiz zaman ThreadStart içine yazmis olugumuz kodlar ilgili thread tarafindan islenmeye baslar.

Public Sub ProgressBar1Doldur()
	While progressBar1.Value < 100
		progressBar1.Value += 1
		Thread.Sleep(10)
	End While
End Sub

Public Sub ProgressBar2Doldur()
	While progressBar2.Value < 100
		progressBar2.Value += 1
		Thread.Sleep(60)
	End While
End Sub

Public Sub ProgressBar3Doldur()
	While progressBar3.Value < 100
		progressBar3.Value += 1
		Thread.Sleep(50)
	End While
End Sub

Her thread olusturulurken belirlenmis olan fonksiyon içindeki kodlari çalistirir ve fonksiyonda ki islemler bittigi zaman otomatik olarak sonlanir.

Asagidaki formu dizaynini yapip yukaridaki gibi bir kod yazar ve derlerseniz "Çapraz is parçacigi islemi geçerli degil: 'progressBar1' denetimine olusturuldugu is parçacigi disinda baska bir is parçacigindan erisildi." Diye bir hata alirsiniz. Bunun sebebi threadlerin senkronlanmadigindandir. Bir threadin kullandigi bir nesneye baska bir thread erismeye çalistigi anda yukaridaki hatayi alirsiniz. Bu hatayi almamak için threadleri senkron olarak çalistirmaniz gerekiyor. Threadleri senkron olarak çalistirma konusuna daha sonra girecegiz. Simdilik yukaridaki hatayi engellemek için threadleri çalistirmadan ince asagidaki kodu ekleyin. Bu kod thread çakismalarini görmezden gelir ve program çalismasini devam eder.

System.Windows.Forms.Form.CheckForIllegalCrossThreadCalls = False

Dim thread1 As New Thread(New ThreadStart(ProgressBar1Doldur))
Dim thread2 As New Thread(New ThreadStart(ProgressBar2Doldur))
Dim thread3 As New Thread(New ThreadStart(ProgressBar3Doldur))

thread1.Start()
thread2.Start()
thread3.Start()

Birde kronometre uygulamasi yapalim. Bir uygulamada ayni anda iki kronometre çalistiralim ve sonucu gözlemleyelim.

Uygulamada görüldügü gibi SingleThread ve MultiThread kullanarak baslat tusuna basarak uygulamalarimizi deniyelim. SingleThread formumuzda kronometre uygulamalarini baslattigimizda Kronometre 1 uygulamasi baslayacak ama Kronometre 2 uygulamasi basla butonuna bastigimiz halde baslamayacaktir ayrica program kronometre 1 islemini bitirene kadar donma islemi yasayacaktir. Fakat MultiThread formumuzdaki kronometre uygulamalarini çalistirdigimizda programimiz sorunsuzca çalismaya baslayacaktir.

MultiThread.vb kodlarimiz;

Imports System
Imports System.Threading
Imports System.Runtime.InteropServices
Public Class MultiThread
    Dim t1 As New System.Threading.Thread(AddressOf Me.MultiThread1)
    Dim t2 As New System.Threading.Thread(AddressOf Me.MultiThread2)
    Private Sub MultiThread_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        CheckForIllegalCrossThreadCalls = False
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Button1.Enabled = False
        t1.IsBackground = True
        t1.Start()
        'MultiThread1()
    End Sub

    Public Sub MultiThread1()
        For index = 1 To 100000
            Me.Label1.Text = index.ToString()
            Me.Refresh()
            System.Threading.Thread.Sleep(50)
        Next
    End Sub
    Public Sub MultiThread2()
        For index = 1 To 100000
            Me.Label2.Text = index.ToString()
            Me.Refresh()
            System.Threading.Thread.Sleep(50)
        Next
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click

        ' is parçaciginin arka plan is parçacigi olup olmadigini belirten bir deger alir veya ayarlar
        t2.IsBackground = True
        t2.Start()
        'MultiThread2()
    End Sub

    Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
        t1.Suspend()
        Button1.Enabled = False
        Button3.Enabled = False
        Button4.Enabled = True
    End Sub

    Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
        Button1.Enabled = False
        Button3.Enabled = True
        Button4.Enabled = False
        t1.Resume()
    End Sub
End Class

SingleThread.vb kodlarimiz;

Imports System
Imports System.Threading
Public Class SingleThread

    Private Sub SingleThread_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        CheckForIllegalCrossThreadCalls = False
    End Sub

    Public Sub SingleThread1()
        For index = 1 To 10000
            Me.Label1.Text = index.ToString()
            Me.Refresh()
        Next
    End Sub
    Public Sub SingleThread2()
        For index = 1 To 10000
            Me.Label2.Text = index.ToString()
            Me.Refresh()
        Next
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        SingleThread1()
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        SingleThread2()
    End Sub

End Class

Abort Metodu

Çalisan Thread’in programatik olarak durdurulmasi yani çizelgeleme disina çikartilmasi için kullanilir. Lakin çagrildigi anda hemen threadin çalismasini durdurmaz. Bunun sebebi, Start metodu gibi asenkron bir sekilde çalismasidir.

Abort metodu ile durdurulmus bir Thread, Start metodu ile tekrardan baslatilamaz.

Suspend ve Resume Metodu

Suspend metodu ile Thread geçici olarak durdurulabilir. Yani çizelgeleme disina çikartilabilir. Suspend ile geçici olarak durdurulmus Thread Resume metodu ile kaldigi yerden devam ettirilebilir.

Burada dikkatinizi çekerim ki, Multi Thread yaklasimlarda bu iki metodun kullanimindan mümkün mertebe kaçinmanizi tavsiye ederim. Bunun nedeni, Suspend ile durdurulmus bir threadin diger threadlar ile paylasimli olarak kullandigi kaynaklarda çikardigi Deadlock diye nitelendirdigimiz muhtemel sorunlardir.

Deadlock Nedir?

Hemen yeri gelmisken Deadlock üzerine biraz konusalim.
Deadlock aslinda processlerin hiçbir zaman ulasamayacaklari bir birim yahut kaynaga ihtiyaç duymalari durumudur. Durum böyle olunca processlerin askida kalmalari diye özetleyebiliriz. Yani bir processi askida birakacak her islem olasi deadlock durumuyla karsilasmamizi saglayabilir. Örnegin; bir process bir diger processin isini bitirmesini beklerken ayni sekilde o processinde diger processin isini beklemesi durumudur. Yani çikmaza girmektir.

Sleep Metodu

Aslinda bizlere fazla yabanci olmayan Sleep metodu, teknik olarak aldigi milisaniye cinsinden deger kadar threadi durdurmamizi saglayan(çizelgeleme disina çikartan) static bir metotdur.

Burada dikkat etmeniz gereken nokta, Sleep metoduna verilen süre sonunda thread tekrar devreye giremeyebilir. Bunun nedeni, Win32 sistemlerinin Real Time(Gerçek Zamanli) isletim sistemleri olmayisidir.

Join Metodu

Düsünün ki, bir threadi sonlandirmak istiyorsunuz ama ilgili thread içerisinde kullanilan diger threadlarin son bulmasi sartiyla…

Iste Join metodu bu islevi görmektedir.

Verilen süre periyodunda threadi kontrol eden ve geriye durumla ilgili bool bir deger döndüren Join metodunu yukaridaki gibi while döngüsü araciligiyla kullanarak ilgili threadi takip edebilir ve islemlerimizi gerçeklestirebiliriz.

ThreadState Propertysi

Ilgili threadin herhangi bir x anindaki durumunu bizlere vermektedir.

Priority Propertysi

Threadin öncelik düzeyinin belirlenmesini saglar. Varsayilan olarak Normal degerine sahiptir.

IsAlive Propertysi

Threadin herhangi bir x aninda aktiflik durumunu verir.

IsAlive propertys’i üzerinde çalistirilan kanal halen çalisiyorsa true degerini aksi halde false degerini döndürür bu da bize avantajlar saglamaktadir. IsBackGround özelligi ise kanalin arka planda çalismasini gerçeklestirir kanalin arkaplanda çalismasini istiyorsaniz IsBackground’a true degerini atamalisiniz. 

' value adinda boolean türünde bir degisken olusturup thread;imizin arka planda çalis çalismadigini kontrol ediyoruz.
        Dim value As Boolean
        value = t1.IsBackground
        Label3.Text = value.ToString

Parçaçik Öncelikleri

Kanallardan bahsederken unutmamiz gereken kanallarin önceligidir. Bir kanalin önceligini CPU belirler. Düsük öncelikli kanallar az CPU zamani, yüksek öncelikli kanallar ise daha fazla CPU zamani gerektirirler. Kullandigimiz kanallar varsayilan bir öncelik atarlar. Varsayilan olarak tüm parçaçiklar islemci tarafindan esit zamanlanir. Tabiki bu önceligi bizim atamamizda mümkün ve böylece daha fazla performans elde edebiliriz. Bunun içinde Thread sinifinin üyesi olan Priority özelligini kullanabiliriz. 
         

         5 adet öncelik atamasi mevcuttur. Bunlar sirasiyla; 

         Highest 
         AboveNormal 
         Normal 
         BelowNormal 
         Lowest 


         Olusturdugumuz kanala biz bir öncelik atamassak varsayilan olarak Normal atanacaktir. 

        t1.Name = "ThreadOne"
        t2.Name = "ThreadTwo"
        t1.Priority = ThreadPriority.Highest
        t2.Priority = ThreadPriority.BelowNormal
        t1.Start()
        t2.Start()

Olusturdugumuz kanala biz bir öncelik atamassak varsayilan olarak Normal atanacaktir. Öncelik atamasi ile ilgili açikca önceliklerin ve CPU zamanini test eden bir örnek yapalim ve bu zamanlamayi görelim. 

Konsoldan çalisan örnegimiz: 

Imports System.Threading

Module ThreadingPriority

    Dim loopSwitchValue As Boolean
    Dim threadOne As System.Threading.Thread = New System.Threading.Thread(AddressOf ThreadMethod)
    Dim threadTwo As System.Threading.Thread = New System.Threading.Thread(AddressOf ThreadMethod)
    Sub Main()

        threadOne.Name = "ThreadOne"
        threadOne.Priority = ThreadPriority.Highest
        threadTwo.Name = "ThreadTwo"
        threadTwo.Priority = ThreadPriority.BelowNormal
        threadOne.Start()
        threadTwo.Start()

        '20 Saniye 
        Thread.Sleep(20000)
        LoopSwitch = False
        Console.ReadLine()
    End Sub

    Sub New()
        loopSwitchValue = True
    End Sub

    WriteOnly Property LoopSwitch() As Boolean
        Set(ByVal value As Boolean)
            loopSwitchValue = value
        End Set
    End Property

    Sub ThreadMethod()

        Dim threadCount As Long = 0
        While loopSwitchValue
            threadCount += 1
        End While
        'Console.WriteLine("{0} with {1} priority " & "has a count = {2}", threadOne.Name, threadOne.Priority.ToString(), threadCount.ToString())

        Console.WriteLine("{0} with {1} priority has a count = {2}", System.Threading.Thread.CurrentThread.Name, System.Threading.Thread.CurrentThread.Priority.ToString(), threadCount.ToString("N0"))

    End Sub

End Module

  • 0
  • 3544
  • 0

- BUNLARIDA GÖZDEN GEÇİREBİLİRSİNİZ -

HENÜZ YORUM YAPILMAMIŞ !

Yorum yazın

HAKKIMDA

KONULARI TAKİP EDİN

SOSYAL AĞLAR

  • Mesajınızı Gonderin