C# dilinde bir thread, aynı anda birden fazla iş parçacığını yürütebilen ve bu sayede çoklu görevler gerçekleştirmeyi mümkün kılan bir yapıdır. Thread’ler, bir programın çeşitli bölümlerinin eşzamanlı olarak çalışmasını sağlar ve bu da genellikle performansı artırır veya kullanıcıya daha duyarlı bir deneyim sunar.
Thread’ler, işletim sistemi düzeyindeki iş parçacığı (thread) kavramına dayanır. Bu iş parçacıkları, CPU zaman dilimleri içinde çalışırlar ve aynı anda birden fazla thread çalışabilir. Bu nedenle, bir programın içinde birden fazla thread kullanarak farklı işlemleri eşzamanlı olarak gerçekleştirmek mümkündür.
C# dilinde thread’ler genellikle System.Threading namespace’i altında Thread sınıfı kullanılarak oluşturulur.
Thread kullanımı anlamak için aşağıdaki senaryomuzu ele alalım. Aşağıdaki programımızda Ürün Listeleme ve Raporlama için iki metot vardır. Kullanıcı menüden seçimini yaparak istediği ekranı açabilir. Lakin senkron bir programlama yapısı olduğundan dolayı programın şöyle bir handikabı vardır. Kullanıcı ekran seçimi yaptıktan sonra tekrar ekran seçim yapabilmek için tüm ürünlerin listelenmesi beklemek zorundadır.
namespace TutorialThreadFirst;
internal class Program
{
static void Main(string[] args)
{
bool devamMi = true;
while (devamMi)
{
Console.WriteLine("İşlem seçiniz:");
Console.WriteLine("1-Ürünleri Listele, 2-Rapor Yazdır, 3-Çıkış");
string Islem = Console.ReadLine();
if (Islem == "1")
UrunListele(); //Bu işlem seçildiğinde kaydetme işlemi bitinceye kadar menü gelmeyecektir.
else if (Islem == "2")
RaporYazdir();
else if (Islem == "3")
devamMi = false;
}
}
static void UrunListele()
{
Console.WriteLine("Ürünler Listeleniyor...");
for (int Sayac = 0; Sayac <= 1000; Sayac++)
{
Console.WriteLine("Ürünler - " + Sayac.ToString());
}
Console.WriteLine("Ürünler listelendi. Enter tuşuna basınız..");
Console.ReadLine();
}
static void RaporYazdir()
{
Console.WriteLine("Rapor Yazdırılıyor...");
for (int Sayac = 0; Sayac <= 1000; Sayac++)
{
Console.WriteLine("Rapor - " + Sayac.ToString());
}
Console.WriteLine("Rapo Yazdırıldı. Enter tuşuna basınız..");
Console.ReadLine();
}
}
Thread kullanıldığında ise, ürünlerin listelenmesi beklemeden menü tekrar kullanılabilir veya ürunler listelenirken eş zamanlı olarak rapor yazdırılabilir.
namespace TutorialThreadSecond
{
internal class Program
{
static void Main(string[] args)
{
bool devamMi = true;
while (devamMi)
{
Console.WriteLine("İşlem seçiniz:");
Console.WriteLine("1-Ürünleri Listele, 2-Rapor Yazdır, 4-Tüm İşlemler, 5-Çıkış");
string Islem = Console.ReadLine();
if (Islem == "1")
{
//Yeni bir thread oluştur: Bu satırda thread (iş parçacığı)'ın hangi metodu çağıracağı belirtilmiştir.
Thread ThreadUrunListele = new Thread(new ThreadStart(UrunListele));
//Thread'i başlat: UrunListele metodunu çağırarak thread (iş parçacağının)'ın paralel çalışmasını sağlar.
ThreadUrunListele.Start();
//Ürünlerin Listelenmesinin bitirilmesi beklenmeden aşağıdaki kod parçacığının çalışmasına devam edilerek menü hemen gelecektir.
}
else if (Islem == "2")
RaporYazdir();
else if (Islem == "3")
devamMi = false;
else if (Islem == "4")
{
Thread ThreadUrunListele = new Thread(new ThreadStart(UrunListele));
Thread ThreadRaporYazdir = new Thread(new ThreadStart(RaporYazdir));
ThreadUrunListele.Start();
ThreadRaporYazdir.Start();
//Ürünlerin Listelenmesi ve Rapor Yazdırılması paralel (eş zamanlı olarak) çalışacaktır.
}
}
}
static void UrunListele()
{
Console.WriteLine("Ürünler Listeleniyor...");
for (int Sayac = 0; Sayac <= 1000; Sayac++)
{
Console.WriteLine("Ürünler - " + Sayac.ToString());
Thread.Sleep(1000);
}
Console.WriteLine("Ürünler listelendi. Enter tuşuna basınız..");
Console.ReadLine();
}
static void RaporYazdir()
{
Console.WriteLine("Rapor Yazdırılıyor...");
for (int Sayac = 0; Sayac <= 1000; Sayac++)
{
Console.WriteLine("Rapor - " + Sayac.ToString());
Thread.Sleep(1000);
}
Console.WriteLine("Rapo Yazdırıldı. Enter tuşuna basınız..");
Console.ReadLine();
}
}
}
Bu bölümde C# dilinde threading (thread yönetimi) konseptine giriş yaptık. Şimdi bu konu başlığı altında bilmeniz gereken bazı temel kavramları açıklayacağım:
Thread Oluşturma: Thread oluşturmak için Thread sınıfından bir örnek oluşturur ve Start metoduyla başlatırsınız.
Thread thread = new Thread(İşYapMetodu);
thread.Start();
Parametreli Thread Oluşturma: Thread’e parametre geçirmek istiyorsanız, ParameterizedThreadStart delegesi veya lambda ifadelerini kullanabilirsiniz:
Thread thread = new Thread(() => İşYapMetodu(parametre));
thread.Start();
Thread Senkronizasyonu: Birden fazla thread’in aynı anda paylaşılan kaynaklara erişmesi durumunda senkronizasyon önemlidir. lock anahtar kelimesi veya diğer senkronizasyon mekanizmalarıyla bu sağlanabilir.
object kilitlemeNesnesi = new object();
lock (kilitlemeNesnesi)
{
// Paylaşılan kaynaklara erişim
}
Thread Bekletme (Join): Ana thread’in diğer thread’in tamamlanmasını beklemesi için Join yöntemi kullanılır. Bu, thread’ler arasında işlemlerin düzenlenmesini sağlar.
Thread thread = new Thread(İşYapMetodu);
thread.Start();
thread.Join(); // Diğer thread tamamlanana kadar bekler
Thread Kesme (Abort): Thread’i aniden durdurmak için Abort yöntemi kullanılabilir. Ancak, bu yöntem kullanıldığında bazı güvenlik riskleri ve beklenmedik sonuçlar olabilir. Bu nedenle, thread’leri güvenli bir şekilde sonlandırmak için diğer teknikler tercih edilir.
thread.Abort(); // Thread'i sonlandır
IsAlive: IsAlive özelliği, bir thread’in hala çalışıp çalışmadığını kontrol etmek için kullanılır. Thread çalışıyorsa true, değilse false döndürür.
if (thread.IsAlive)
{
// Thread hala çalışıyor
}
Interrupt: Interrupt metodu, bir thread’in çalışmasını kesmek için kullanılır. Ancak bu metot genellikle kullanılmaz çünkü beklenmedik hatalara yol açabilir ve thread’in güvenli bir şekilde sonlanmasını zorlaştırabilir.
thread.Interrupt();
Sleep: Sleep metodu, belirtilen süre boyunca bir thread’i uyku moduna alır. Genellikle zamanlayıcı işlemler veya test senaryoları için kullanılır.
Thread.Sleep(1000); // 1 saniye uyku
Name Özelliği: Name özelliği, bir thread’in adını tanımlamak veya değiştirmek için kullanılır. Bu özellik, thread’leri daha kolay tanımlamak ve takip etmek için kullanışlıdır.
Thread thread = new Thread(İşYapMetodu);
thread.Name = "MyThread";
Priority Özelliği: Priority özelliği, bir thread’in öncelik seviyesini belirlemek için kullanılır. Öncelik seviyeleri ThreadPriority enum’u ile belirtilir (en yüksekten en düşüğe: Highest, AboveNormal, Normal, BelowNormal, Lowest).
thread.Priority = ThreadPriority.Highest;
Resume Metodu: Resume metodu, bir thread’i askıya alınmış durumdan (suspended) çalışır duruma getirmek için kullanılır. Ancak bu metot .NET Core 2.0 ve sonraki sürümlerde kullanılmamaktadır. Bunun yerine Monitor.Pulse veya Monitor.PulseAll gibi senkronizasyon mekanizmaları tercih edilir.
thread.Resume(); // Kullanılmamalı
Suspend Metodu: Suspend metodu, bir thread’i çalışır durumdan askıya almak için kullanılır. Ancak bu metot .NET Core 2.0 ve sonraki sürümlerde kullanılmamaktadır. Bunun yerine Monitor.Wait gibi senkronizasyon mekanizmaları tercih edilir.
thread.Suspend(); // Kullanılmamalı
Resume ve Suspend metotları .NET Core 2.0 ve sonraki sürümlerde kullanılmamaktadır çünkü thread’lerin kontrolünü doğrudan değiştirmek yerine daha güvenli ve doğru senkronizasyon mekanizmaları kullanılması tavsiye edilmektedir.
Thread ve Task, C# programlamada çoklu işlem yürütme yöntemleridir ancak aralarında bazı önemli farklar vardır.
Thread:
Örnek Thread kullanımı:
Thread thread = new Thread(() =>
{
// İşlemler
});
thread.Start();
Task:
Örnek Task kullanımı:
Task task = Task.Run(() =>
{
// İşlemler
});
Özetle, Thread daha düşük seviyeli ve doğrudan işletim sistemi üzerinde kontrol sağlarken, Task daha yüksek seviyeli soyutlama ve daha iyi kaynak yönetimi sunar. Task, modern C# uygulamalarında daha yaygın olarak tercih edilen bir yapıdır, özellikle asenkron programlama ve paralel işlemler için.