Bu site emekli olmuştur. Arşiv amaçlı olarak BT AKADEMİ sponsorluğunda yayın hayatına devam etmektedir.




C#nedir?com
 
YAZAR HAKKINDA
Ferhat Nutku
Ferhat Nutku
http://www.csharpnedir.com/
İletişme geçmek için tıklayın.
4 Makalesi yayınlanmakta.
Yazar hakkında detaylı bilgi için tıklayın.
Yayınlanan diğer makaleleri için tıklayın.
İlgili etiketler: birbirlerinin burada isletim istenen kanalin kanallar kullanilan kullanilir. metodu program proses sinifi sinifinin thread thread(new C# / VC#/.NET Ferhat Nutku
 
YAZI HAKKINDA
Türü : Makale
Serbest Köşede C#nedir?com üyelerinin hazırladıkları yazılar yayınlanır. Bu yazılar editör incelemesine girmeden yayınlanır.
Seviyesi : İleri
Kategori : C# / VC#/.NET
Yayınlanma Tarihi : 16.1.2006
Okunma Sayısı : 114761
Yorum Sayısı : 5     yorum yaz
Site İçi AramaSİTE İÇİ ARAMA
Üye Girişini AçÜye GİRİŞİ
Üye girişi için tıklayın.
Kullanıcı Adı
Şifre
 
Beni her zaman hatırla
Bir hafta boyunca kullanıcı bilgilerinizi kullanıcı çıkışı yapana kadar hatırlar. (Paylaşılan bilgisayarlarda önerilmez.)
 
Şifremi / Kullanıcı Adımı unuttum.
 
.net TV RSS Serbest KÖŞE (?)
Serbest Köşede C#nedir?com üyelerinin hazırladıkları yazılar yayınlanır. Bu yazılar editör incelemesine girmeden yayınlanır.
emre TAŞ
Silindi
emre TAŞ
yazının devamı >
emre TAŞ
silindi
emre TAŞ
yazının devamı >
emre TAŞ
silindi
emre TAŞ
yazının devamı >
emre TAŞ
silindi
emre TAŞ
yazının devamı >
emre TAŞ
silindi
emre TAŞ
yazının devamı >
Makale Gönder Bende Yazmak İstiyorum
.net TV RSSBlogroll
Turhal Temizer
Conda install environment.yml Package 29.3.2024
Turhal Temizer
Mac OS/X Removing CUDA 29.3.2024
Burak Selim Şenyurt
Kurumsal Yazılımcının Oyun Geliştirme ile İmtihanı 29.3.2024
Burak Selim Şenyurt
Matematik ve Oyun Programlama - Missile Command - Final 29.3.2024
  Diğer Herşey
Sponsorlar
BT Akademi
Medya Portakal
Video Hosting Sponsoru
Csharpnedir.com bir Ineta üyesidir
Uzman Abi
Her Yönüyle C# - Sefer Algan
C# ile Çok Kanallı (Multithread) Programlamada Senkronizasyon
 
Kapat
Sayfayı Yazdır Sık Kullanılanlara Ekle Arkadaşıma Gönder MySpace Del.Ico.Us Digg Facebook Google Mixx Reddit StumbleUpon
Windows işletim sisiteminin önemli özelliklerinden biri de multithreaded bir mimariye sahip olmasıdır. Peki multithreaded (çok kanallı) program ne demektir ? Genellikle proses ve thread kavramları birbirine karıştırılır. Derlenip çalıştırılan bir programa işletim sistemi içersinde yer alan bir proses denir. Örneğin bir hesap makinası programı ile resim programını ard arda çalıştıralım. Bu iki program işletim sistemi tarafından iki ayrı proses olarak ele alınır. Bu iki program birbirlerinin yaptığı işlemlere müdahale etmez. (İstersek prosesleri birbirlerine müdahale edecek şekilde programlayabiliriz. Genellikle bu istisnayi bir durumdur.) Her proses kendi bellek alanı içersinde koşmaya devam eder. Thread ise bir proses içersinde yer alan ve işlem yapan bir rutindir. Bir proses içersinde birden fazla thread var olabilir. Threadler genellikle bir proses içersinde ayrı kanallarda paralel olarak çalışması istenen metodların yürütülmesinde kullanılır. Bazı thread programlama örnekleri için şu linlerkden faydalanabilirsiniz: Çok Kanallı(Multithread) Uygulamalar, Thread’leri Belli Süreler Boyunca Uyutmak ve Yoketmek, Thread’lerde Öncelik(Priority) Durumları.

Threadler sayesinde ayrı metodları aynı anda çalıştırabiliriz. İşletim sistemi her thread’e çalışması için belli bir zaman aralığı verir. Bu zaman aralığı dolduğunda çalışan thread’den çıkılıp, program içersindeki diğer bir metoda veya başka bir thread’e girilir. Bir metod içersinde yapılan iş ne kadar uzun sürüyorsa o metodun bağlı olduğu thread’de o kadar fazla zaman harcanır. Bazen bu süre o kadar fazla olur ki, proses içersindeki başka bir thread’e çalışması için çok az zaman kalır. Başlatılan threadlerin aynı anda senkron bir şekilde çalışabilmesi için .NET’te senkronizasyon teknikleri kullanılır. Burada aynı andalığı (senkronizasyon) biraz açmamız gerekebilir. Örneğin üç tane kanalımız (thread) olsun. Her bir kanalda bir progressbar dolduruluyor olsun.

public void DegerArttir1()
{
    for (int i = 1; i <= 100; ++i)
    {
        progressBar1.Value += 1;
        lbThreads.Items.Add("Thread 1");
        Thread.Sleep(10);
    }
} public void DegerArttir2()
{
    for (int j = 1; j <= 100; ++j)
    {
        progressBar2.Value += 1;
        lbThreads.Items.Add("Thread 2");
        Thread.Sleep(100);
    }
}

public void DegerArttir3()
{
    for (int k = 1; k <= 100; ++k)
    {
        progressBar3.Value += 1;
        lbThreads.Items.Add("Thread 3");
        Thread.Sleep(150);
    }
}

private void btnStart_Click(object sender, EventArgs e)
{
    th1 = new Thread(new ThreadStart(DegerArttir1));
    th2 = new Thread(new ThreadStart(DegerArttir2));
    th3 = new Thread(new ThreadStart(DegerArttir3));
    th1.Start();
    th2.Start();
    th3.Start();
}



Üç kanal çalıştırıldığında ekran çıktısı aşağıdaki gibi olacaktır. Burada dikkat ederseniz ilk kanalın bağlı olduğu DegerArttir1 metodunda 10 milisaniyelik bir bekleme süresi varken ( Thread.Sleep(10) ), üçüncü kanalın bağlı olduğu DegerArttir3 metodunda 150 milisaniyelik bir bekleme süresi vardır. Süreler arasındaki bu farktan dolayı her kanala ayrılan zaman birbirinden farklıdır. Burada öncelikli kanal th1’dir. Bu yüzden birinci progressbar diğerlerinden önce dolar.
Örnek uygulamayı indirmek için tıklayınız.



Şekil 1. Asenkron kanallarla doldurulan üç progressbar.

Aynı anda çalışan kanallar (senkron threadler) ise birbirlerinin metotlarının işlemlerinin bitmesini bekler. Bir kanal diğer bir kanaldaki işlem bitmeden harekete geçmez. Bu sayede üç kanal senkron bir şekilde çalışır. .NET’te thread senkronizasyonu için dört yöntem kullanılabilir.



Şekil 2. .NET’te thread senkronizasyon teknikleri.

Interlocked :

Interlocked sınıfı birden fazla kanal tarafından kullanılan değişkenler üzerinde çeşitli işlemlerin yapılmasına olanak sağlayan bir sınıftır. Buradaki değişken değer tipinde olabileceği gibi herhangi bir nesne de olabilir. Interlocked sınıfının şimdilik sadece Exchange metodu referans tipleri ile çalışabilir. Exchange’in generic metot olarak tasarlanmış bir overload’u da mevcuttur. Increment, decrement metodları ise Int32, Int64 tipi değişkenleri parametre olarak kabul eder. Interlocked sınıfını şöyle kullanabiliriz:

public void DegerArttirInterlocked1()

{
    try
    {
        while (counter <= 300)

        {
            Interlocked.Increment(ref counter);
            progressBar1.Value += 1;
            lbThreads.Items.Add("Thread 1");
            Thread.Sleep(80);
        }          
    }
    catch { }
}
Burada counter global olarak tanımlanmış olan int değişkendir. Increment fonksiyonu ile counter değişkeni kontrollü arttırılmaktadır. Bir thread altında counter üzerinde işlem yapılırken diğer bir thread içersinde counter üzerinde aynı anda işlem yapılmaz.  

Lock :

Bir kanal içersindeki işlemlerin, diğer bir kanal tarafından müdahale edilmeden çalışabilmesi için lock anahtar kelimesi kullanılır. Lock ile bloklanmış olan işlemler bir kanal içersinde tamamlanıncaya kadar çalışırlar. Bu süre zarfında başka kanallar lock ile bloklanmış işlemlerin bitmesini beklerler. İşlem bitince diğer kanallar kendi metodlarını çalıştırmaya devam eder. Bu şekilde senkronizasyon sağlanabilir. Lock parametre olarak herhangi bir nesne alabilir. Örneğimizde form nesnemizi parametre olarak kullandık.

public void DegerArttirLock1()
{
    for (int i = 1; i <= 100; ++i)
    {
        lock (this)
        {
            progressBar1.Value += 1;
            lbThreads.Items.Add("Thread 1");
            Thread.Sleep(10);
        }
    }
}
Genellikle lock’a aktarılan parametrenin public olmamasına dikkat edilir. Lock ile kilitlenen nesne public ise bu nesne üzerinde işlem yapmak isteyen metodlar (bir thread’e bağlı olmayan) da kilitlenir. Bu tür kilitlenmelere deadlocks (kısır döngü) denir. Bu istenmeyen bir durumdur. Public yerine protected veya private kullanmak bu sorunu çözer. Şekil 3’de DegerArttirLock metodlarını çağıran kanallar çalıştırıldığında progressbar’ların ve kanalların durumu sergilenmiştir. Dikkate edilirse kanallar 123, 123 şeklinde art arda düzgün bir şekilde çağırılmaktadır. Asenkron kanallarda ise 132, 131, 111 şeklinde düzensiz çağırılmalar gerçekleşir.



Şekil 3. Senkron kanallarla doldurulan üç progressbar.

Monitor :

Monitor, nesnelere kanalların senkronize bir şekilde ulaşmasını sağlayan bir sınıftır. Monitor sınıfı referans tipindeki değişkenleri senkronize etmek için kullanılır. Değer tipindeki değişkenler için monitor sınıfı kullanılmaz. Monitor’ün kullanımı lock’un kullanımına benzer. Monitor blokladığı kodların başka kanallar tarafından erişilmesini engeller. Monitor sınıfının bazı metodları aşağıdaki tabloda özetlenmiştir. 

Metod Görevi
Enter, TryEnter Bloklanmak istenen nesne Enter ile Monitor nesnesine kayıt ettirilir.
Diğer kanallar bu bloklanan nesneye müdahale edemez. Nesne artık kilitlenmiştir.
Monitor.Enter ile bloklanmak istenen kodlar için lock’a benzer şekilde başlangıç verilebilir.
Wait Bloklanmış nesne üzerindeki kilidi açar. Diğer kanallar nesneye ulaşabilir ve onu kilitleyebilir.
Pulse, PulseAll Bir kanaldaki kilitlenmiş nesnenin, üzerindeki kilidin kaldırılacağını bekleyen kanallara duyurmak için kullanılır. Diğer kanallar kendi kuyruklarına kilidi açılacak olan nesneyi kayıt ederler. Pulse, Exit metodu öncesi kullanılan bir metottur ve ana amacı diğer kanallara kilidin açılacağını önceden duyurmaktır.
Exit Nesne üzerindeki kilidi açar.
Monitor.Exit ile bloklanmak istenen kodlar için lock’a benzer şekilde sonlanma noktası verilebilir.
Tablo 1. Monitor sınıfının bazı metodları.

Monitor sınıfının DegerArttir fonksiyonunda nasıl kullanılacağı aşağıda gösterilmiştir. Kısır döngüler (deadlock) ile karşılaşmamak için monitorObject nesnesinin üzerindeki kilit finally bloğunda  herzaman kaldırılmaktadır.

private object monitorObject = new object();
public void DegerArttirMonitor1()
{
    for (int i = 1; i <= 100; ++i)
    {
        try
        {
            Monitor.Enter(monitorObject);
            progressBar1.Value += 1;
            lbThreads.Items.Add("Thread 1");
            Thread.Sleep(10);
            Monitor.Pulse(monitorObject);
        }
        finally
        {
            Monitor.Exit(monitorObject);
        }
    }
}
Mutex :

Mutex sınıfı monitor sınıfına benzer ancak System.Threading.WaitHandle sınıfından türetilmiştir ve türediğin sınıfın daha kolay kullanılabilir bir genelleştirilmesidir. Mutex sınıfı kanallar tarafından ortak kullanılan nesnelere aynı anda ulaşılıp, işlem yapılmasını engellemek için kullanılır. Mutex sınıfı ortak kullanılan kaynaklara bir t zamanında sadece bir kanalın ulaşabilmesini garanti eder. Mutex kendisini kullanan kanalın tekilliğini (identity) kontrol eder. Bir mutex’e sahip olan kanal WaitOne metodu ile onu kilitler ve ReleaseMutex metodu ile mutex’i serbest bırakır. Bir mutex kullanan kanal sadece kendi mutex’ini ReleaseMutex metodu ile açabilir. Kanallar birbirlerinin mutex’lerini serbest bırakamaz. Bizim örneğimizde progressbar’ların tam anlamı ile aynı anda ilerlemediğini fark edeceksiniz. Burada mutex’i sadece ortak kaynaklara güvenli erişim amacı ile kullandık.

private object mutexObject = new object();
public void DegerArttirMutex1()
{
    for (int i = 1; i <= 100; ++i)
    {
        mutexObject.WaitOne();
        progressBar1.Value += 1;
        lbThreads.Items.Add(>"Thread 1");
        Thread.Sleep(10);
        mutexObject.ReleaseMutex();
    }
}
Semaphore :

Semaphore sınıfı .NET 2.0 framework ile gelen yeni bir sınıftır. Bu sınıf da System.Threading.WaitHandle sınıfından türetilmiştir. Semaphore sınıfının Mutex sınıfından farkı, farklı kanalların birbirlerinin Semaphore’larının kilitlerini Release metodu ile açabilmeleridir. Bir kanal semaphore’un WaitOne metodunu birçok kez çağırabilir. Bu kilitleri açmak için art arda Release metodunu çağırabileceği gibi, Release(int) overload’unu da kullanabilir. Semaphore kendisini kullanan kanalın identity’sine bakmaz. Bu yüzden farklı kanallar birbirlerinin semaphore’larının WaitOne ve Release metodlarını çağırabilir. Herbir WaitOne metodu çağırıldığında semaphore’un sayacı bir azaltılır. Herbir release metodu çağırıldığında ise sayaç bir arttırılır. Semaphore’un yapılandırıcısında (constructor) sayacın minimum ve maksimum değerleri belirlenebilir.

private Semaphore semaphoreObject = new Semaphore(0,2);
public void DegerArttirSemaphore1()
{
    for (int i = 1; i <= 100; ++i)
    {
        semaphoreObject.WaitOne();
        progressBar1.Value += 1;
        lbThreads.Items.Add("Thread 1");
        Thread.Sleep(10);s
        semaphoreObject.Release();
    }
}

private void btnSemaphore_Click(object sender, EventArgs e)
{
    th1 = new Thread(new ThreadStart(DegerArttirSemaphore1));
    th2 = new Thread(new ThreadStart(DegerArttirSemaphore2));
    th3 = new Thread(new ThreadStart(DegerArttirSemaphore3));
    th1.Start();
    th2.Start();
    th3.Start();
    semaphoreObject.Release(2);
}
Sonuç :



Bu makalede threadlerin senkronizasyonunu ve threadler tarafından ortak olarak kullanılan kaynakların nasıl yönetilebileceğini inceledik. Çok kanallı programlamada karşılaşılan en büyük sorun kısırdöngü (deadlock) denilen programın kilitlenmesine yol açan kodlardır. Kısır döngülerden kurtulmak için ortak kullanılan değişkenler ve nesneler yukarıda anlatılan teknikler ile izole edilmelidir. Böylece bir proses içersinde birçok kanalda birçok metodu paralel bir şekilde çalıştırabiliriz.Ferhat Nutku
[email protected]
Makale:
C# ile Çok Kanallı (Multithread) Programlamada Senkronizasyon C#, Visual C# ve .NET Ferhat Nutku
  • Yazılan Yorumlar
  • Yorum Yaz
ŞUB
23
2013
"Cross-thread operation not valid" hatasını düzelterek, programı tekrar sunabilir misiniz.
NİS
30
2010
"Cross-thread operation not valid" hatasını önlemek için kodun şu şekilde olması gerekiyor. private void button1_Click(object sender, EventArgs e) { th1 = new Thread(new ThreadStart(RunnerProgressBar1)); th1.Priority = ThreadPriority.BelowNormal; th1.Start(); } private void RunnerProgressBar1() { if (progressBar4.InvokeRequired) { progressBar4.Invoke(new DlgFillProgressBar1(FillProgressBar1)); } } private delegate void DlgFillProgressBar1(); private void FillProgressBar1() { for (int i = 0; i < 100; i++) { progressBar4.Value += 1; Thread.Sleep(80); } }
NİS
28
2010
Makale çok eğitici, elinize sağlık. Ancak program malesef "Cross-thread operation not valid" hatası veriyor. Bu normal mi, düzeltmek için ne yapılabilir?
ŞUB
18
2006
makale için tebrik ederim gerçekten çok güzel bir şekilde thread leri anlatmışsınız. thread mantığı olsun örnekler olsun hepsi çok güzel. Benim size sorum olacak delegate lerle ilgili böyle bir makale yazmayı düşünürmüsünüz.
Sayfalar : 1 
Yorum yazabilmek için üye girişi yapmalısınız. Üye girişi için tıklayın.
Üye değilseniz Üyel Ol linkine tıklayarak üyeliğinizi hemen başlatabilirisniz.
 
  • Bu Konuda Son 10
  • Eklenen Son 10
  • Bu Konuda Geçmiş 10
Bu Konuda Yazılmış Yazılmış 10 Makale Yükleniyor
Son Eklenen 10 Makale Yükleniyor
Bu Konuda Yazılmış Geçmiş Makaleler Yükleniyor