Yükleniyor...

C# Process ve Thread Yönetimi

C#’ta process ve thread yönetimini öğrenin. Çok iş parçacıklı yapı, süreç kontrolü ve sistem kaynaklarıyla çalışma örneklerle.

Modern uygulamalarda birden fazla görevi aynı anda yerine getirmek için işlem (process) ve iş parçacığı (thread) kavramları kullanılır. C# ve .NET, bu iki yapıyı yönetmek için güçlü API’ler sunar. Process bir uygulamanın çalışan örneğidir; Thread ise o işlem içinde paralel çalışan alt akışlardır. Bu makalede süreç (process) başlatma, iş parçacığı (thread) yönetimi, senkronizasyon ve paralel çalışmanın temelleri anlatılmaktadır.


Process (İşlem) Nedir?

Her çalışan uygulama, işletim sistemi tarafından bir process olarak temsil edilir. Bir process’in kendi bellek alanı, kaynakları ve çalışan thread’leri vardır. .NET’te process yönetimi için System.Diagnostics.Process sınıfı kullanılır.


using System;
using System.Diagnostics;

class Program
{
    static void Main()
    {
        // Yeni bir Not Defteri işlemi başlat
        Process.Start("notepad.exe");

        // Çalışan tüm işlemleri listele
        foreach (var proc in Process.GetProcesses())
        {
            Console.WriteLine($"{proc.ProcessName} - ID: {proc.Id}");
        }
    }
}

Process.Start() metodu yeni bir uygulama başlatırken, GetProcesses() tüm çalışan işlemleri getirir.


Bir Process Üzerinde İşlemler Yapmak

Process nesnesi üzerinden çalışan uygulamaya erişebilir, kapatabilir veya bekletebilirsiniz.


using System;
using System.Diagnostics;
using System.Threading;

class Program
{
    static void Main()
    {
        // Not defteri başlat
        var p = Process.Start("notepad.exe");

        // 3 saniye bekle
        Thread.Sleep(3000);

        // Kapat
        p.Kill();

        Console.WriteLine("Not Defteri kapatıldı.");
    }
}

Bu örnekte process 3 saniye sonra sonlandırılır. Dikkat: Kill() metodu zorla sonlandırma yapar; işlemde açık dosya veya veri kaybı olabilir.


Thread (İş Parçacığı) Nedir?

Thread, bir process içindeki yürütme birimidir. Varsayılan olarak her uygulama bir ana (main) thread ile başlar. Farklı görevleri paralel yürütmek için ek thread’ler oluşturulabilir.


using System;
using System.Threading;

class Program
{
    static void Main()
    {
        Thread t = new Thread(SelamVer);
        t.Start();

        for (int i = 0; i < 3; i++)
        {
            Console.WriteLine("Main thread çalışıyor...");
            Thread.Sleep(500);
        }

        t.Join(); // Thread’in bitmesini bekler
        Console.WriteLine("Program sonlandı.");
    }

    static void SelamVer()
    {
        for (int i = 0; i < 3; i++)
        {
            Console.WriteLine("Selam thread çalışıyor...");
            Thread.Sleep(400);
        }
    }
}

Bu örnekte iki thread aynı anda çalışır. Join(), thread’in tamamlanmasını bekler.


Thread Priority (Öncelik) ve Durum Yönetimi

Her thread’in bir Priority (öncelik) değeri ve ThreadState (durum) özelliği vardır. Thread önceliği CPU zamanlamasını etkileyebilir.


Thread t1 = new Thread(() =>
{
    Console.WriteLine("Düşük öncelikli iş.");
});
t1.Priority = ThreadPriority.Lowest;

Thread t2 = new Thread(() =>
{
    Console.WriteLine("Yüksek öncelikli iş.");
});
t2.Priority = ThreadPriority.Highest;

t1.Start();
t2.Start();

Console.WriteLine($"t1 durumu: {t1.ThreadState}");
Console.WriteLine($"t2 durumu: {t2.ThreadState}");

Not: İşletim sistemi thread önceliğini dikkate alır, ancak bu garanti değildir; zamanlayıcıya bağlıdır.


Thread Güvenliği ve Senkronizasyon

Birden fazla thread aynı kaynağa (örneğin değişken, liste veya dosya) eriştiğinde senkronizasyon gerekir. Aksi halde “race condition” (yarış durumu) oluşabilir.


using System;
using System.Threading;

class Program
{
    static int sayac = 0;
    static object kilit = new object();

    static void Main()
    {
        Thread t1 = new Thread(Arttir);
        Thread t2 = new Thread(Arttir);

        t1.Start();
        t2.Start();

        t1.Join();
        t2.Join();

        Console.WriteLine($"Sonuç: {sayac}");
    }

    static void Arttir()
    {
        for (int i = 0; i < 1000; i++)
        {
            lock (kilit)
            {
                sayac++;
            }
        }
    }
}

lock anahtar kelimesi aynı anda yalnızca bir thread’in kilitli bloğa girmesini sağlar. Bu sayede veri tutarsızlığı önlenir.


ThreadPool ile Hafif Thread Yönetimi

ThreadPool, kısa ömürlü işler için thread oluşturma maliyetini azaltır. .NET, mevcut thread havuzundan boşta olan thread’leri otomatik kullanır.


using System;
using System.Threading;

class Program
{
    static void Main()
    {
        for (int i = 0; i < 5; i++)
        {
            int id = i;
            ThreadPool.QueueUserWorkItem(_ =>
            {
                Console.WriteLine($"İş {id} başlatıldı (Thread ID: {Thread.CurrentThread.ManagedThreadId})");
                Thread.Sleep(500);
            });
        }

        Console.WriteLine("Tüm işler gönderildi.");
        Thread.Sleep(2000); // ThreadPool’un bitmesini bekle
    }
}

ThreadPool genellikle kısa süren ve sık tekrarlanan görevlerde tercih edilir (örneğin HTTP istekleri, log işlemleri).


Process ve Thread Arasındaki Fark

ÖzellikProcessThread
TanımÇalışan programın örneğiProcess içinde paralel çalışan yürütme birimi
Kaynak KullanımıKendi belleği vardırAynı bellek alanını paylaşır
BağımsızlıkBağımsız çalışırProcess’e bağlıdır
Oluşturma MaliyetiYüksekDüşük
İletişimIPC (Inter-Process Communication) gerekirPaylaşılan bellek ile kolay iletişim

Örnek: Paralel Dosya İndirme

Aşağıdaki örnekte her dosya indirme işlemi ayrı thread’lerde çalıştırılır. Böylece birden fazla dosya aynı anda indirilebilir.


using System;
using System.Net;
using System.Threading;

class Program
{
    static void Main()
    {
        string[] dosyalar = {
            "https://example.com/dosya1.jpg",
            "https://example.com/dosya2.jpg",
            "https://example.com/dosya3.jpg"
        };

        foreach (var url in dosyalar)
        {
            new Thread(() => DosyaIndir(url)).Start();
        }

        Console.WriteLine("İndirmeler başlatıldı...");
    }

    static void DosyaIndir(string url)
    {
        string ad = Path.GetFileName(url);
        using var client = new WebClient();
        client.DownloadFile(url, ad);
        Console.WriteLine($"{ad} indirildi. (Thread: {Thread.CurrentThread.ManagedThreadId})");
    }
}

Bu örnek, IO tabanlı işlemlerde paralel çalışmanın büyük hız kazandırabileceğini gösterir.


Performans ve Dikkat Edilecekler


TL;DR

  • Process, çalışan bir programın örneğidir; kendi bellek alanına sahiptir.
  • Thread, process içinde paralel çalışan görev akışıdır; belleği paylaşır.
  • ThreadPool kısa ve çok sayıda görev için uygundur.
  • lock senkronizasyon için kullanılır, veri tutarlılığını sağlar.
  • Fazla thread açmak kaynak israfına yol açabilir; Task veya async tercih edin.

İlişkili Makaleler