Bu yazımızda size c# ile multithreading programlamaya küçük bir giriş yapacağım. Multithreading kavramı türkçeye çok kanallı programlama diye çevrilmiş; bunu da belirtmekte fayda var, en azından bu şekilde ne olduğuna ilişkin bir fikir sahibi olabilirsiniz.
Çok kanallı programlama Nedir?
Çok kanallı programlama şuan siz bu yazıyı okurken karşınızda olan şeydir. Muhtemelen bu yazıyı okurken yalnızca internet tarayıcınız çalışmıyor bilgisayarınızda; bir tarafta müzik çalıcı, bir tarafta antivirüs yazılımı, bir tarafta mesajlaşma yazılımınız çalışır vaziyette, hatta belki de bunu okurken biri ile sesli görüşme bile yapıyor olabilirsiniz.
İşte bu şekilde bir bilgisayarda aynı anda birden fazla programın çalışması işine çok kanallı çalışma diyoruz.
Çok kanallı programlamada da biz yalnızca bir program içinde aynı anda çalışan birden fazla küçük işlemleri çalıştıracağız. Burada şunu unutmamak gerekir; çok kanallı programlama demek yalnızca işletim sisteminde birden fazla uygulamanın çalışması değil aynı program içinde de birden fazla işlemin (thread) aynı anda çalışması demektir.
Programlamaya C veya Pascal gibi yapısal (modüler) dillerle başlayanlar bilirler; bir kod akış grafiği vardır, program alt rutinden(fonksiyon, prosedür) altrutine dallanır, akar ve biter. Böylesi bir mantıkla örneğin MS Word 2000 gibi bir programın çalışmasını anlamak mümkün değildir. Bu program aynı anda hem sizin yaınızı alan (scanf gibi bir işlem), hem yazdıklarınızı denetleyen ve yanlış yazıları işaretleryen, hem ara ara dosyanızı kaydeden, resim ve diğer dosyaların oynatma ve yerleştirme işlemlerini yapan, hem de yazıcıdan çıktı üreten bir yazılımdır. Siz bunu bir noktadan başlayıp adım adım işleleri yapan komple bir yapı olarak kurgulamaya çalıştığınızda işin içinden çıkamazsınız. İşte çok kanallı programlama ile her bir alt işlemi ayrı bir kanalda (yolda) çalışacak şekilde programlayıp aynı anda hepsinin çalışmasını sağlamak multithreadi'tir.
Şimdi c# dili ile bu işlemin nasıl yapılacağına değinelim.
Önce bir thread'in aslında bizim kullandığımız fonksiyonlardan pek de farklı olmadığını (en azından bu mantıkla kullanabileceğimizi belirtmek gerek, yani ortada tümüyle yeniden öğrenmeyi gerektirecek bir şey yok.
Şimdi iki tane koşucumuz olsun ve biz bu koşucuları yarıştıralım. Bir buton ile yarışı başlatalım ve butonun işlevine de iki koşucunun yarışa başması için gerekli başlangıç kodunu yazalım ve sonucu görelim.
Alıntı:
public void kosucu1()
{
for(int i=0;i<100;i++)
{
System.Threading.Thread.Sleep(1);
Application.DoEvents();//bunlar döngüde herşeyin yolunda gitmesi için kullanılıyor
}
label1.Text = "Ben birinci kosucuyum";
}
public void kosucu2()
{
for(int i=0;i<100;i++)
{
System.Threading.Thread.Sleep(1);
Application.DoEvents();//bunlar döngüde herşeyin yolunda gitmesi için kullanılıyor
}
label2.Text = "Ben ikinci koşucuyum";
}
Kodumuzu bu şekilde yazıp çalıştırdığımızda önce label1'de "Ben birinci koşucuyum", biraz sonra da label2'de "Ben ikinci koşucuyum" yazdığını göreceksiniz. Bunun anlamı birinci koşucumuzun yarışı kazandığıdır ancak burada bir adaletszlik söz konusu. Çünkü buton1'in kodunda önce koşucu1'in yarışını bitirmesini sağlayan kosucu1(); fonksiyonunu yazdık, bu fonksiyon icra edildi, label1'e yazı yazıldı, sonra ikincis koşucunun fonksiyonuna geçildi. Bu da her zaman koşucu1'in birinci olacağı, aslında bunu bir yarış olmadığı anlamına gelir.
Peki ya şöyle olsaydı: Biz butona bastığımızda aynı anda iki koşucu da başlasa ve hangisi daha önce hedefe varırsa o ilk önce "Vardım" diye yazsa. İşte bunun için Thread'ları kullanacağız.
Thread'larla ilgili iki temel veri tipi (sınıf, temsilci) kullanacağız; şimdi bunların hem örneklerini verelim, hem de anlatalım:
Biri ThreadStart biri de Thread olmak üzre ikişer değişken kullandık. ThreadStart bir Thread'ın başlatılması için kullanılan bir sınıftır. Bu sınıfa eşzamanlı çalıştırmak istediğimiz fonksiyonun ismini verdiğimizde bize bir Thread oluşturmak için gerekli hazırlığı yapar. Thread sınfı ile de oluşan bu işi (thread) yönetiriz.
Buton1'e tıklandığında çalışan kodu şu şekilde değiştirelim:
Alıntı:
private void button1_Click(object sender, System.EventArgs e)
{
t_baslat1 = new System.Threading.ThreadStart(kosucu1);
t_baslat2 = new System.Threading.ThreadStart(kosucu2);
t1 = new System.Threading.Thread(t_baslat1);
t2 = new System.Threading.Thread(t_baslat2);
t1.Start();
t2.Start();
}
Gördüğünüz gibi önce ThreadStart ile fonksiyonları aldık, sonra da bu Thread başlatıcıları Thread sınıflarına verdik. Bütün hazırlıklar bittiğinde ise
Alıntı:
t1.Start()
gibi bir fonksiyon ile bu işi başlattık. Kodu bu şekilde derleyip çalıştırdığımızda hoş bir sonuç ile karşılaşacağız. For döngülerine verdiğimiz değerler aynı olduğu için bu iki fonksiyonun icra süreleri aynıdır, yaklaşık olarak aynı anda başladıkları için de aynı anda label1'de "Ben birinci koşucuyum", label2'de de "Ben ikinci koşucuyum" yazısı çıkacaktır.
Şimdi işler kızıştı Şimdi koşucu1 ve koşucu2 fonksiyonlarına gidip döndülerin değelerinde küçük değişiklikler yapın. Örneğin koşucu1'in döngü sayısını 100'den 300'e çıkarın; bu kez koşucu 2'nin çok daha erken hedefe varacağını, koşucu1'in ise ondan 200 milisaniye sonra geleceğini görün.
Tamam ayrı işlemleri ayrı kanallardan oluşturduk. Peki bunların dışında bir işlemi yönetmek için gerekli olan başka bir araç yok mu? Tabii ki var. Bir Threadin başlatılması, durdurulması, duraklatılması ve durduğu yerden devam etmesi gerekir çoğu zaman işte bu işlemler için gerekli fonksiyonlar şöyle;
Alıntı:
t1.Suspend();
Bir işi tıpkı winamp programında çalan şarkıyı "pause" ettiğiniz gibi durdurur.
Alıntı:
t1.Resume();
Çalan şarkıyı kaldığı yerden devam ettirir Suspend metodu ile durdurulmuş işi kaldığı yerden devam ettirir.
Alıntı:
t1.Abort();
Devam eden işlemi sonlandırır, bitirir. Abort ile sonlanmış işlem geri döndürülmez.
Alıntı:
t1.ThreadState
Bununla Threadin durumunu öğreniriz
Alıntı:
t1.IsAlive
Bununla threadin hala hayatta olup olmadığını öğreniriz.
Alıntı:
t1.Priority
Bu değer hem okunabilir, hem de yazılabilirdir. Bununla threadimizin öncelik değerini öğrenir veya değiştirebiliriz (belirleyebiliriz).
Bir oyun yazdınız; oyunda kullanıcının hareket ettirdiği bir adam ve bilgisayarın yönettiği, adamınızı yakalamaya çalışan böcekler var. Böyle bir oyunu yapısal bir programlama dili ile yazarken ya adamınızın ve böceklerin hızları aynı olacak ya da böcekler adamınızın hareket etme döngüsü içinde bir hareket edecekler, bir etmeyecekler ve hızları adamın hızının yarısı olacak. Her şeyden önce böyle bir kodlama korkunç karışık ve verimsiz olur. Oysa çok kanallı programlama ile her bir robotu (adam ve böcekler) ayrı ayrı programlar farklı kanallardan çalıştırırsanız hem kodlamanız kolay hem de programınız daha etkili olur.
Bu basit örnek sadece anlaşılması içindi oysa çok kanallı programlamanın kullanım yeri bu tür alt seviye işlemlerle sınırlı değildir. Bugün kullandığınız profesyonel programların hemen hepsi multithreading destekli yazılmıştır.
Ancak çok kanallı programlamanın da bir zayıf noktası vardır.
Malum şu an kullandığımız bilgisayarların çoğu tek işlemci kullanıyor ve bir işlemci aslında aynı anda sadece bir işlem yapabilir. Aynı anda çalışıyormuş gibi çalışan programlar çok küçük parçalara bölünür, her bir zaman biriminde ilk programın bir parçası, sonra ikinci programın bir parçası ... son programın bir parçası ve sonra tekrar ilk program en son çalıştırılan parçadan itibaren diğer arçası çalıştırılır. Çok hızlı yapılan bu işlem bütün programların aynı anda çalışıyormuş gibi hissedilmesine sağlar. Burada önemli olan işlemcinin bu görev parçacıkları arasındaki geçişidir. Az sayıda program varken bu pek sorun olmaz ancak program sayısı çoğaldıkça görevler arası geçiş çok zaman almaya başlar ve işlemci sırf görev geçişleri yüzünden kafasını kaldıracak zaman bulamaz. Çok kanallı programlama verimli bir uygulama iken böylesi bir durumda verim düşer. İşlemcinin bu şekilde kalmasına "açlıktan ölme" (starvation) denir. Bu sebeple çok kanallı programlama uygulanırken boş yere threadlar çoğaltılmamalı işlemcinin ve belleğin durumu göz önünde bulundurulmalıdır.
Programın tam halini (daha doğrusu basit bir örneği) sisteme yüklemek istedim ama sanıyorum bir sorun var; o yüzden buraya kodları yapıştırıyorum:
Alıntı:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
C# ile multithreading programlamaya giriş Öncelikle güzel bi konu ona sölemek lazım ..multithreading..yanı basitçe aynı anda birden fazla işlem yapma..
tabı bu c# olabileceği gibi diğer dillerde olabiilir... şimdi c# hakkında bi kaç not ekleyim ben 2000 senesinde c++ dan sonra c# yazılmış ve oldukça iddaali bir dildir. ve .net teknolojisinin ise resmi dili sayılmaktadır.Ki şuanda da microsoft hemen hemen tüm cabası .net üzerindedir. Şimdi gelelim kodlarını nasıl çalıştıcağı hakkında bi kaç şey diyim ben. öncelikle frameworks yükleyin sonra ise visual c# yüklemeniz lazım nesne eklemek için .. kolay gelsin ..