Chargement...

Gestion des processus et des threads en C#

Apprenez la gestion des processus et des threads en C# pour contrôler l’exécution et les ressources système.

Dans les applications modernes, les concepts de processus et de thread sont utilisés pour exécuter plusieurs tâches simultanément. C# et .NET offrent des API puissantes pour gérer ces deux structures. Un processus est une instance d’un programme en cours d’exécution, tandis qu’un thread est un flux d’exécution parallèle à l’intérieur de ce processus. Cet article explique les bases du démarrage de processus, de la gestion des threads, de la synchronisation et de l’exécution parallèle.


Qu’est-ce qu’un Processus ?

Chaque application en cours d’exécution est représentée par le système d’exploitation comme un processus. Un processus possède sa propre mémoire, ses ressources et ses threads actifs. En .NET, la gestion des processus se fait via la classe System.Diagnostics.Process.


using System;
using System.Diagnostics;

class Program
{
    static void Main()
    {
        // Démarrer un nouveau processus Bloc-notes
        Process.Start("notepad.exe");

        // Lister tous les processus en cours
        foreach (var proc in Process.GetProcesses())
        {
            Console.WriteLine($"{proc.ProcessName} - ID: {proc.Id}");
        }
    }
}

La méthode Process.Start() lance une nouvelle application, tandis que GetProcesses() récupère tous les processus en cours d’exécution.


Travailler avec un Processus

Vous pouvez interagir avec une application en cours via son objet processus : l’arrêter, l’attendre ou la suspendre.


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

class Program
{
    static void Main()
    {
        // Démarrer le Bloc-notes
        var p = Process.Start("notepad.exe");

        // Attendre 3 secondes
        Thread.Sleep(3000);

        // Fermer
        p.Kill();

        Console.WriteLine("Bloc-notes fermé.");
    }
}

Dans cet exemple, le processus est arrêté après 3 secondes. Attention : la méthode Kill() met fin au processus de manière forcée, ce qui peut entraîner une perte de données non enregistrées.


Qu’est-ce qu’un Thread ?

Un thread est une unité d’exécution au sein d’un processus. Par défaut, chaque application démarre avec un thread principal. Des threads supplémentaires peuvent être créés pour exécuter plusieurs tâches en parallèle.


using System;
using System.Threading;

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

        for (int i = 0; i < 3; i++)
        {
            Console.WriteLine("Le thread principal est en cours d’exécution...");
            Thread.Sleep(500);
        }

        t.Join(); // Attendre la fin du thread
        Console.WriteLine("Programme terminé.");
    }

    static void Saluer()
    {
        for (int i = 0; i < 3; i++)
        {
            Console.WriteLine("Le thread de salutation est en cours d’exécution...");
            Thread.Sleep(400);
        }
    }
}

Dans cet exemple, deux threads s’exécutent simultanément. La méthode Join() attend la fin du thread.


Priorité et État d’un Thread

Chaque thread possède une valeur Priority et un état ThreadState. La priorité d’un thread peut influencer la planification du processeur.


Thread t1 = new Thread(() =>
{
    Console.WriteLine("Tâche à faible priorité.");
});
t1.Priority = ThreadPriority.Lowest;

Thread t2 = new Thread(() =>
{
    Console.WriteLine("Tâche à haute priorité.");
});
t2.Priority = ThreadPriority.Highest;

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

Console.WriteLine($"État de t1 : {t1.ThreadState}");
Console.WriteLine($"État de t2 : {t2.ThreadState}");

Remarque : Le système d’exploitation prend en compte la priorité des threads, mais cela dépend du planificateur et n’est pas garanti.


Sécurité et Synchronisation des Threads

Lorsque plusieurs threads accèdent à la même ressource (par exemple une variable, une liste ou un fichier), une synchronisation est nécessaire. Sinon, une condition de concurrence peut se produire.


using System;
using System.Threading;

class Program
{
    static int compteur = 0;
    static object verrou = new object();

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

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

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

        Console.WriteLine($"Résultat : {compteur}");
    }

    static void Incremente()
    {
        for (int i = 0; i < 1000; i++)
        {
            lock (verrou)
            {
                compteur++;
            }
        }
    }
}

Le mot-clé lock garantit qu’un seul thread à la fois peut accéder au bloc protégé, évitant ainsi toute incohérence de données.


Gestion Légère des Threads avec ThreadPool

Le ThreadPool réduit le coût de création de nouveaux threads pour des tâches de courte durée. .NET réutilise automatiquement les threads disponibles à partir d’un pool partagé.


using System;
using System.Threading;

class Program
{
    static void Main()
    {
        for (int i = 0; i < 5; i++)
        {
            int id = i;
            ThreadPool.QueueUserWorkItem(_ =>
            {
                Console.WriteLine($"Tâche {id} démarrée (Thread ID : {Thread.CurrentThread.ManagedThreadId})");
                Thread.Sleep(500);
            });
        }

        Console.WriteLine("Toutes les tâches ont été soumises.");
        Thread.Sleep(2000); // Attendre la fin du ThreadPool
    }
}

Le ThreadPool est idéal pour les tâches courtes et répétitives (par exemple les requêtes HTTP ou la journalisation).


Différences entre Processus et Thread

PropriétéProcessusThread
DéfinitionInstance d’un programme en cours d’exécutionUnité d’exécution parallèle dans un processus
Utilisation de la mémoirePossède sa propre mémoirePartage la mémoire du processus
IndépendanceFonctionne indépendammentDépend du processus
Coût de créationÉlevéFaible
CommunicationNécessite une communication inter-processus (IPC)Facile via la mémoire partagée

Exemple : Téléchargement de Fichiers en Parallèle

Dans l’exemple ci-dessous, chaque téléchargement de fichier s’exécute dans un thread distinct, permettant le téléchargement simultané de plusieurs fichiers.


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

class Program
{
    static void Main()
    {
        string[] fichiers = {
            "https://example.com/fichier1.jpg",
            "https://example.com/fichier2.jpg",
            "https://example.com/fichier3.jpg"
        };

        foreach (var url in fichiers)
        {
            new Thread(() => TelechargerFichier(url)).Start();
        }

        Console.WriteLine("Téléchargements commencés...");
    }

    static void TelechargerFichier(string url)
    {
        string nom = Path.GetFileName(url);
        using var client = new WebClient();
        client.DownloadFile(url, nom);
        Console.WriteLine($"{nom} téléchargé. (Thread : {Thread.CurrentThread.ManagedThreadId})");
    }
}

Cet exemple montre que l’exécution parallèle peut considérablement accélérer les opérations d’entrée/sortie.


Performances et Recommandations


TL;DR

  • Processus : Instance d’un programme avec son propre espace mémoire.
  • Thread : Flux d’exécution parallèle dans un processus partageant la mémoire.
  • ThreadPool : Idéal pour de nombreuses tâches courtes.
  • lock : Assure la synchronisation et la cohérence des données.
  • Trop de threads entraînent un gaspillage de ressources ; privilégiez Task ou async pour plus d’efficacité.

Articles connexes