Multithreading & Asynchronous Programlama
Concurent : Aynı zamanda olan olayları tanımlamak için kullanılır. Multithreaded : Çoklu yürütme içeriklerini tanımlar. Parallel : Aynı anda gerçekleşen işlemler paralel işlemler olrak isimlendirilir. Asynchronous : Bekleme gerektirmeyen işlemlerde kullanılır.
Multithreading
Process in Yapısı Process bir tür depodur. Kendi sanal adres uzayı (virtual address space) vardır. Bir process in içeriği diğer bir process tarafından adreslenmez. Kod kütüphaneleri bu adres uzayına haritalanırlar.
Process ve Thread Thread ler kodu icra ederler (execution). Thread, bir process deki tüm kod boyunca var olan icra yoludur. Bir process deki tüm dataya veya hiçbirine erişebilir. Her bir thread in kendi callstack ı ve CPU registerlerinin kopyası vardır. Thead i olmayan process çalışmasını bitirir.
Çoklu Threadlerin Kullanım Alanları CPU ya bağlı işlemlerin paralelleştirilmesine olanak verir. (multi-core / multi-processor desteği ile) I/O işlemleri nedeniyle bekleme yaşanırken CPU ya bağlı işlemlerin gerçekleşmesini sağlar. UI nin kullanıcıya cevap verebilen (responsive) şekilde olmasına olanak sağlar.
Sanılanın aksine tek işlemci tek bir core a sahip olan makine üzerinde de çok thread li yapı kullanılabilir. Böyle bir durumda ise;
Çok thread li program yazımı aşağıdaki sonuçları doğurur. Program karmaşıklığını arttırır. Kod sayısı artar. Okunabilirlik ve yönetilebilirliğin önüne geçer. Debug yapmak zorlaşır. Test etmek zorlaşır.
Thread olarak çalıştırılacak olan metotların imzası aşağıdaki şekilde olmalıdır: void EntryPointMethod() void EntryPointMethod(object statearg)
Nesne üzerinden tanımlanmış olan metotlar da farklı bir thread şeklinde çalıştırılabilirler.
Thread lerin Yaşam Süreleri (Lifetime) Yürütme, thread in çalışmaya başladığı noktaya dönünceye kadar devam eder. Thread çalışmasını 3 tür şekilde sonlandırır. Görevini tamamlayıp çalışmaya başladığı noktaya geri döndüğünde, Çalışmasını sırasında thread in kendinden meydana gelecek bir exception meydana geldiğinde, Diğer herhangi bir thread in çalışmakta olan thread i Interrupt() ve Abort() metotlarını çağırmasıyla. IsAlive özelliği ile thrad in hangi evrede olduğu öğrenilebilir.
Sonlandırırken Koordinasyon
Thread Pool CLR her process için bir thread pool sağlar. Eş zamanlı işlemler için bu havuzdan threadleri ödünç alır. Gelen istekler doğrultusunda havuzdan threadler alınır veya iade edilir. Havuzdan alınan threadlerin IsBackground özellikleri true olarak belirtilir. Thread havuzu ile 3 farklı şekilde etkileşime girmek mümkündür. ThreadPool.QueueUserWorkItem Delegate.BeginInvoke Asynchronous I/O
ThreadPool.QueueUserWorkItem
Delegate Temsilciler thread havuzuna arayüzler sağlar. Hatırlanacağı gibi delegate ler fonksiyon göstericileridir. BeginInvoke metotdu ile delegate ile işaret edilmiş metot Thread havuzundan istekte bulunur.
Senkronizasyon (Synchronization)
Birçok kaynağa eş-zamanlı olarak (concurrently) erişmek mümkün değildir. Kaynaklar; Kolleksiyonlar(diziler, linked-list ler, vd.) Dosyalar Intgeter gibi temel veri türleri olabilir.
Böyle bir durumda, program ekrana hangi değeri basmalıdır? Gerçekte hangi değeri basmaktadır?
Yarış Durumu (Race Condition) HATA
Çözüm 1 Birçok işlemci kelime boyutunda atomik güncellemeleri desteklemektedir.
FCL, işlemciden bağımsız olarak atomik güncellemeleri gerçekleştirebilir. Bunun için System.Threading.Interlocked sınıfı içerisindeki metotlar kullanılır.
Çözüm 2 Bazen, veri seti bir çok thread in çalışmasına imkan verecek şekilde parçalara ayrılır (data partitioning). Bu tekniğin uygulanabilmesi için problemin bu tarz bir çözüme uygun olması gerekmektedir.
Çözüm 3 (Bekleme temelli zamanlama) (Wait-Based Synchronization) Bazen, threadler aynı kaynağa (parçalara ayrılamayan) erişime ihtiyaç duyarlar. Verideki bağımlılıklar (data dependency) veri setini parçalanmasını olanaksız kılar. Örn: Fibonacci işlemi islem[0] = islem[1]=1 islem[n] = islem[n-1]+ islem[n-2] Bu gibi durumlarda wait-based yaklaşımıyla senkronizasyon sağlanır. Thread izin verilinceye kadar bloklanmak durumunda kalınır.
Bu teknik programcı tarafından isteyerek gerçekleştirilir. Öncelikli olarak paylaşılan kaynak (shared resource) belirlenir. Senkronizasyonu sağlayacak araç belirlenir (Monitor, Mutex vb) Belirlenen bu aracın bir örneği (instance) kullanılarak bloklama işlemi gerçekleştirilir. Kaynağa erişmek isteyen bir thread; Kaynağın sahipliğini elde etmeli Ardından kaynağa ulaşmalı Sonrasında ise sahipliği bırakır.
CLR da pek çok wait-based senkronizasyon tekniği bulunmaktadır. Monitor Mutex ReaderWriterLockSlim ManualResetEvent, AutoResetEvent Semaphore System.Threading namespace inde bulunan sınıflar
System.Threading.Monitor CLR, belirli bir zamanda sadece tek bir threadin monitöre girmesine izin verir. Diğer threadler bloklanır. Thread kaynak ile işi bittiğinde monitor den çıkar.
Tut ve Bekle Hold & Wait Bazen bir thread bir kilidi tutarken beklemesi gerekebilir. Kaynağın yeniden beslenmesi vb. Diğer bir anahtar Bu gibi senaryolar Hold&Wait senaryosu olarak nitelendirilir.
Ölümcül Kilitlenmeler (DeadLocks) Hold-wait senaryosunun olduğu bütün durumlarda deadlock oluşabilir. Örn: bir thread bir kilide sahipken, diğer bir kilide de sahip olmak isteyebilir. Eğer iki veya daha fazla thread aynı kilit için yarışıyorlarsa deadlock oluşabilir. Sistemde çok fazla sayıda thread, işlemci veya core varsa deadlock oluşması muhtemeldir. Eğer kilitlerde zamanlama faktörü kullanılırsa deadlock geçici süreyle oluşur.
Mutex Mutex, Win32 kernel nesnesidir. System.Threading.Mutex, yönetilebilir kod için FCL wrapper sağlar. Zaman aşımı limitli kilit edinimlerini destekler. Aynı makine üzerinde processler arası thread senkronizasyonuna izin verir. Elde edilmesi ve salınması için kernel mode ile etkileşime geçmeyi gerektirir.
Zamanlamaya bağlı olaraktan bir kilit başka bir thread tarafından ele geçirilmiş olabilir. Böyle bir durum ise ölümcül kilitlenmeye neden olacaktır.
Asenkron Programlama ve Task Parallel Library (TPL)
Asynchronous Programlama Yükleme sembolünü ekranda göster Asenkron işlemi başlat Büyük boyutlu bir CSV dosyasını diskten oku Her bir satırı say Asenktron işlemi bitir Sonucu ekranda göster Yükleme sembolünü ekrandan kaldır.
Asynchronous ve Parallel Programlama Yükleme sembolünü ekranda göster Asenkron işlemi başlat Büyük boyutlu bir CSV dosyasını diskten oku Her bir satırı paralel bir şekilde say Asenktron işlemi bitir Sonucu ekranda göster Yükleme sembolünü ekrandan kaldır.
Amaç
Async & Parallel Programlama Her ikisi de Tasklara ve TPL kütüphanesini temel alır..net 4.0 dan itibaren desteklenmektedir. TPL in alternatifleri nelerdir? Threadler Asenkron delegate çağrıları (Async delegate invocation) Arka planda çalışan sınıflar QueueUserWorkItem TPL in avantajı nedir? Kolay exception yönetimi Kolay iptal edilebilme Daha az deadlock
Thread & Task İş parçacığı (thread), processin en küçük yürütme birimidir. Bir processin çok sayıda threadi olabilir. Diğer bir deyişle iş parçacığı (thread), bir process deki tüm kod boyunca var olan icra yoludur. Task, iş birimidir (unit of work). Sürmekte olan bir işleme veya hesaplamaya işaret eden bir nesnedir.
Task Oluşturmak(En Basit Yöntem)
Code-based task lar threadler tarafından icra edilirler. Thread task bitinceye kadar ilgili taskla ilişkilidir.
Task ın Sonlandırılması Task, code bloğu sonlandığında veya exception fırlatarak sonlanır.
Continuation
Task Oluşturmak(Yöntem 2)
TPL i kullanırken lambda ifadelerinden yararlanmak mümkündür.