Wird geladen...

Prozess- und Threadverwaltung in C#

Lernen Sie Prozess- und Threadverwaltung in C#, um Ausführung, Ressourcen und Multithreading zu steuern.

In modernen Anwendungen werden die Konzepte von Prozessen und Threads verwendet, um mehrere Aufgaben gleichzeitig auszuführen. C# und .NET bieten leistungsstarke APIs zur Verwaltung dieser beiden Strukturen. Ein Prozess ist eine laufende Instanz eines Programms, während ein Thread ein parallel ausgeführter Ablauf innerhalb dieses Prozesses ist. In diesem Artikel werden die Grundlagen des Startens von Prozessen, der Thread-Verwaltung, der Synchronisation und der parallelen Ausführung erläutert.


Was ist ein Prozess?

Jede laufende Anwendung wird vom Betriebssystem als Prozess dargestellt. Ein Prozess verfügt über seinen eigenen Speicherbereich, seine Ressourcen und seine laufenden Threads. In .NET wird die Prozessverwaltung über die Klasse System.Diagnostics.Process durchgeführt.


using System;
using System.Diagnostics;

class Program
{
    static void Main()
    {
        // Einen neuen Notepad-Prozess starten
        Process.Start("notepad.exe");

        // Alle laufenden Prozesse auflisten
        foreach (var proc in Process.GetProcesses())
        {
            Console.WriteLine($"{proc.ProcessName} - ID: {proc.Id}");
        }
    }
}

Die Methode Process.Start() startet eine neue Anwendung, während GetProcesses() alle aktuell laufenden Prozesse abruft.


Mit einem Prozess arbeiten

Über ein Prozessobjekt kann auf eine laufende Anwendung zugegriffen, sie beendet oder pausiert werden.


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

class Program
{
    static void Main()
    {
        // Notepad starten
        var p = Process.Start("notepad.exe");

        // 3 Sekunden warten
        Thread.Sleep(3000);

        // Beenden
        p.Kill();

        Console.WriteLine("Notepad wurde beendet.");
    }
}

In diesem Beispiel wird der Prozess nach 3 Sekunden beendet. Achtung: Die Methode Kill() beendet den Prozess sofort – offene Dateien oder nicht gespeicherte Daten können verloren gehen.


Was ist ein Thread?

Ein Thread ist eine Ausführungseinheit innerhalb eines Prozesses. Standardmäßig startet jede Anwendung mit einem Hauptthread. Zusätzliche Threads können erstellt werden, um verschiedene Aufgaben parallel auszuführen.


using System;
using System.Threading;

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

        for (int i = 0; i < 3; i++)
        {
            Console.WriteLine("Hauptthread läuft...");
            Thread.Sleep(500);
        }

        t.Join(); // Auf das Ende des Threads warten
        Console.WriteLine("Programm beendet.");
    }

    static void Gruessen()
    {
        for (int i = 0; i < 3; i++)
        {
            Console.WriteLine("Begrüßungs-Thread läuft...");
            Thread.Sleep(400);
        }
    }
}

In diesem Beispiel laufen zwei Threads gleichzeitig. Join() wartet, bis der Thread beendet ist.


Thread-Priorität und Zustandsverwaltung

Jeder Thread hat einen Priority-Wert und eine ThreadState-Eigenschaft. Die Priorität eines Threads kann die CPU-Zuteilung beeinflussen.


Thread t1 = new Thread(() =>
{
    Console.WriteLine("Niedrig priorisierte Aufgabe.");
});
t1.Priority = ThreadPriority.Lowest;

Thread t2 = new Thread(() =>
{
    Console.WriteLine("Hoch priorisierte Aufgabe.");
});
t2.Priority = ThreadPriority.Highest;

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

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

Hinweis: Das Betriebssystem berücksichtigt Thread-Prioritäten, jedoch ist das Verhalten nicht garantiert und hängt vom Scheduler ab.


Thread-Sicherheit und Synchronisation

Wenn mehrere Threads gleichzeitig auf dieselbe Ressource (z. B. Variable, Liste oder Datei) zugreifen, ist Synchronisation erforderlich. Andernfalls kann es zu einem sogenannten Race Condition kommen.


using System;
using System.Threading;

class Program
{
    static int zaehler = 0;
    static object sperre = new object();

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

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

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

        Console.WriteLine($"Ergebnis: {zaehler}");
    }

    static void Erhoehen()
    {
        for (int i = 0; i < 1000; i++)
        {
            lock (sperre)
            {
                zaehler++;
            }
        }
    }
}

Das Schlüsselwort lock stellt sicher, dass immer nur ein Thread gleichzeitig in den blockierten Abschnitt eintreten kann, wodurch Dateninkonsistenzen verhindert werden.


Leichtgewichtige Thread-Verwaltung mit ThreadPool

Der ThreadPool reduziert die Kosten für die Erstellung neuer Threads bei kurzlebigen Aufgaben. .NET verwendet automatisch verfügbare Threads aus einem gemeinsamen Pool.


using System;
using System.Threading;

class Program
{
    static void Main()
    {
        for (int i = 0; i < 5; i++)
        {
            int id = i;
            ThreadPool.QueueUserWorkItem(_ =>
            {
                Console.WriteLine($"Aufgabe {id} gestartet (Thread-ID: {Thread.CurrentThread.ManagedThreadId})");
                Thread.Sleep(500);
            });
        }

        Console.WriteLine("Alle Aufgaben wurden eingereiht.");
        Thread.Sleep(2000); // Auf Abschluss der ThreadPool-Aufgaben warten
    }
}

Der ThreadPool eignet sich besonders für kurze, häufig wiederkehrende Aufgaben (z. B. HTTP-Anfragen oder Logging).


Unterschied zwischen Prozess und Thread

EigenschaftProzessThread
DefinitionInstanz eines laufenden ProgrammsAusführungseinheit innerhalb eines Prozesses
SpeichernutzungEigener SpeicherbereichGemeinsam genutzter Speicher
UnabhängigkeitLäuft unabhängigAbhängig vom Prozess
ErstellungskostenHochNiedrig
KommunikationErfordert IPC (Inter-Process Communication)Einfache Kommunikation über gemeinsamen Speicher

Beispiel: Paralleler Dateidownload

Im folgenden Beispiel wird jeder Datei-Download in einem eigenen Thread ausgeführt, sodass mehrere Dateien gleichzeitig heruntergeladen werden können.


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

class Program
{
    static void Main()
    {
        string[] dateien = {
            "https://example.com/datei1.jpg",
            "https://example.com/datei2.jpg",
            "https://example.com/datei3.jpg"
        };

        foreach (var url in dateien)
        {
            new Thread(() => DateiHerunterladen(url)).Start();
        }

        Console.WriteLine("Downloads gestartet...");
    }

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

Dieses Beispiel zeigt, dass parallele Ausführung die Leistung bei IO-basierten Operationen erheblich steigern kann.


Leistungs- und Sicherheitsaspekte


TL;DR

  • Prozess – Eine laufende Instanz eines Programms mit eigenem Speicherbereich.
  • Thread – Ein paralleler Ausführungsfluss innerhalb eines Prozesses, der Speicher teilt.
  • ThreadPool – Geeignet für kurze und häufige Aufgaben.
  • lock – Wird für Synchronisation und Datenkonsistenz verwendet.
  • Zu viele Threads verschwenden Ressourcen; bevorzugen Sie Task oder async für mehr Effizienz.

Ähnliche Artikel