Gestion des processus dans les systèmes répartis

Cette leçon traite de la gestion des processus dans les systèmes répartis, en se concentrant particulièrement sur la notion de processus, la communication entre processus, les threads et leur gestion en Java, ainsi que l'application du multithreading dans les architectures client/serveur. Elle s'inscrit dans un cours sur les systèmes distribués.

D'après le document Gestion des processus dans les systèmes répartis

Cet article a été rédigé automatiquement à partir du document source, puis vérifié avant publication.

Gestion des processus dans les systèmes répartis

Document source

Gestion des processus dans les systèmes répartis

Distributed Systems · PDF · 17 pages · 2009

Afficher l'aperçu du document

Consulter le document original →

Cette leçon traite de la gestion des processus dans les systèmes répartis, en se concentrant particulièrement sur la notion de processus, la communication entre processus, les threads et leur gestion en Java, ainsi que l'application du multithreading dans les architectures client/serveur. Elle s'inscrit dans un cours sur les systèmes distribués.

Notion de processus et relations entre processus

Un processus est un programme en cours d'exécution. Il représente une activité à laquelle sont attribuées des ressources, et dont l'état évolue dans le temps. Cette unité abstraite d'exécution est indépendante des ressources physiques telles que le processeur ou la mémoire. Ainsi, un processeur peut exécuter plusieurs processus simultanément en pseudo-parallélisme, tandis que sur une machine multiprocesseur, plusieurs processus peuvent s'exécuter réellement en parallèle.

Les processus ne sont pas toujours indépendants. Ils peuvent être en compétition pour des ressources partagées comme le processeur, la mémoire ou une imprimante, ce qui peut entraîner des attentes et des blocages. Ils peuvent aussi coopérer pour atteindre un objectif commun, par exemple lorsqu'un processus crée une image, un autre l'affiche, et un troisième l'imprime. Cette coopération nécessite souvent une synchronisation pour que certains processus attendent des événements produits par d'autres.

Communication entre processus

La communication inter-processus (IPC) est un aspect fondamental de la programmation système. Plusieurs moyens existent :

  • Signaux : un processus peut se bloquer en attendant un signal, qui déclenche l'exécution de fonctions spécifiques à son arrivée.
  • Mémoire partagée : si le système d'exploitation le permet, des segments de mémoire partagée peuvent être utilisés, comme sous UNIX.
  • Communication par fichiers : via un système de fichiers local ou distribué (exemple : NFS).
  • Sockets : pour la communication réseau, mais aussi en local.
  • Middleware : incluant RPC, files de messages, objets distribués, etc.

La communication inter-processus est coûteuse en raison des changements de contexte, mais elle est sécurisée, évitant la corruption des données.

Threads : définition et gestion

Un thread, ou fil d'exécution, est une partie des instructions d'un processus en cours d'exécution. Il est souvent considéré comme un processus léger. Un processus peut contenir plusieurs threads (multithreading) qui s'exécutent en parallèle, en pseudo-parallélisme ou en parallélisme réel.

Contrairement aux processus, les threads partagent le même espace d'adressage et les mêmes ressources, ce qui facilite la communication mais expose au risque de corruption des données. Le multithreading améliore la performance globale et la transparence des applications, par exemple un serveur multithreadé peut continuer à accepter des connexions tout en traitant d'autres requêtes.

Différences entre thread et processus

Aspect Processus Thread
Support Peut supporter plusieurs threads Attaché à un seul processus
Unité Unité d'allocation (changement de contexte) Unité d'exécution
Communication Coûteuse Faible coût
Fiabilité Garantie par l'OS Risque de corruption des données
Performances Limitée par changement de contexte Bonnes

Création et gestion des threads en Java

Java offre deux moyens principaux pour créer des threads :

  • Hériter de la classe Thread : il faut étendre la classe java.lang.Thread et redéfinir la méthode run().
  • Implémenter l'interface Runnable : une classe implémente Runnable et définit la méthode run(). Un thread est ensuite créé en passant une instance de cette classe au constructeur de Thread.

Voici un exemple simple d'une classe étendant Thread :

class SimpleThread extends Thread {
  String stringToPrint;
  SimpleThread(String S) {
    this.stringToPrint = new String(S);
  }
  public void run() {
    while (true) {
      System.out.println(stringToPrint);
      this.yield();
    }
  }
  public static void main(String args[]) {
    SimpleThread T1 = new SimpleThread("Bonjour !");
    SimpleThread T2 = new SimpleThread("Bonsoir !");
    T1.start();
    T2.start();
  }
}

Le résultat alterne l'affichage des deux messages "Bonjour !" et "Bonsoir !" de manière concurrente.

Exemple avec Runnable :

class SimpleRunnable implements Runnable {
  String stringToPrint;
  SimpleRunnable(String S) {
    this.stringToPrint = new String(S);
  }
  public void run() {
    while (true) System.out.println(stringToPrint);
  }
  public static void main(String args[]) {
    Thread T = new Thread(new SimpleRunnable("Bonjour"));
    T.start();
  }
}

Interruption des threads en Java

La classe Thread fournit des méthodes pour gérer l'interruption des threads :

  • void interrupt() : interrompt un thread.
  • boolean isInterrupted() : retourne true si le thread a été interrompu.

Exemple d'un thread qui s'arrête proprement lorsqu'il est interrompu :

class NiceThread extends Thread {
  public void run() {
    while (!isInterrupted()) {
      System.out.println("From : " + getName());
    }
    System.out.println("Clean up operations");
  }
}

public class InterruptTest {
  public static void main(String args[]) throws InterruptedException {
    NiceThread missManners = new NiceThread();
    missManners.setPriority(2);
    missManners.start();
    Thread.currentThread().sleep(2);
    missManners.interrupt();
  }
}

Concurrence et protection contre les accès concurrents

Les threads partagent les mêmes ressources, ce qui peut entraîner des incohérences. Une opération apparemment atomique peut être décomposée en plusieurs sous-opérations par le système ou la JVM, provoquant des erreurs en cas d'accès concurrent.

Exemple de problème de concurrence :

class Concurrent extends Thread {
  public static int c = 0;
  static void increment() throws Exception {
    int local;
    for (int i = 0; i < 1000; i++) {
      local = c;
      local++;
      Thread.sleep(1);
      c = local;
    }
  }
  public void run() {
    try {
      increment();
    } catch (Exception e) {}
  }
  public static void main(String args[]) throws Exception {
    Concurrent T1 = new Concurrent();
    Concurrent T2 = new Concurrent();
    T1.start();
    T2.start();
    T1.join();
    T2.join();
  }
}

La valeur finale de c peut être incorrecte à cause des accès concurrents non synchronisés.

Pour éviter cela, Java propose le mot-clé synchronized qui protège les sections critiques et assure une exclusion mutuelle :

class Concurrent extends Thread {
  public static int c = 0;
  static synchronized void increment() throws Exception {
    int local;
    for (int i = 0; i < 1000; i++) {
      local = c;
      local++;
      Thread.sleep(1);
      c = local;
    }
  }
  public void run() {
    try {
      increment();
    } catch (Exception e) {}
  }
  public static void main(String args[]) throws Exception {
    Concurrent T1 = new Concurrent();
    Concurrent T2 = new Concurrent();
    T1.start();
    T2.start();
    T1.join();
    T2.join();
    System.out.println(c);
  }
}

Chaque objet possède un verrou associé. Lorsqu'un thread appelle une méthode synchronisée, il doit obtenir ce verrou. Si le verrou est détenu par un autre thread, le thread appelant est mis en attente. Le verrou est libéré lorsque le thread sort du bloc synchronisé.

Attention, synchroniser une méthode statique bloque l'accès à toute la classe. Java permet aussi de protéger des blocs de code spécifiques avec synchronized. Pour des mécanismes plus avancés, la bibliothèque java.util.concurrent.locks offre des fonctionnalités supplémentaires.

Multithreading dans les applications client/serveur

Le multithreading peut être utilisé aussi bien côté client que côté serveur :

  • Serveur multithreadé : un thread accepte les connexions entrantes, tandis que d'autres threads traitent les requêtes des clients.
  • Client multithreadé : permet de contacter plusieurs serveurs quasi-simultanément.

Exemple d'un serveur multithreadé en Java

Le serveur écoute sur un port donné et crée un thread distinct pour chaque connexion client. Chaque thread exécute une tâche (Worker) qui envoie la date au client après un délai, puis ferme la connexion.

import java.io.*;
import java.net.*;
import java.util.*;

class MultithreadedDateServer implements Runnable {

  class Worker implements Runnable {
    Socket Soc;
    public Worker(Socket S) {
      this.Soc = S;
    }
    public void run() {
      try {
        PrintWriter out = new PrintWriter(Soc.getOutputStream(), true);
        Thread.sleep(10 * 1000);
        out.println(new java.util.Date().toString());
        Soc.close(); // Fermeture de la connexion
      } catch (Exception ex) {
        System.out.println(ex);
      }
    }
  } // fin Worker

  public void run() {
    try {
      ServerSocket welcomeSocket = new ServerSocket(6789);
      while (true) {
        Socket client = welcomeSocket.accept();
        Thread T = new Thread(new Worker(client));
        T.start();
      }
    } catch (Exception ex) {
      System.out.println(ex);
    }
  }

  public static void main(String argv[]) throws Exception {
    Thread t = new Thread(new MultithreadedDateServer());
    t.start();
    Thread.sleep(59 * 1000);
    System.out.println("59 secondes écoulées... le serveur va s'arrêter");
    t.stop();
  }
}

Ce serveur illustre la gestion concurrente des clients grâce au multithreading, améliorant la réactivité et la capacité de traitement simultané.

Points clés

  • Un processus est un programme en cours d'exécution, pouvant contenir plusieurs threads.
  • Les processus peuvent être en compétition ou en coopération, nécessitant souvent une synchronisation.
  • La communication inter-processus utilise divers mécanismes (signaux, mémoire partagée, sockets, middleware).
  • Un thread est une unité d'exécution légère partageant les ressources du processus.
  • Java permet de créer des threads en héritant de Thread ou en implémentant Runnable.
  • La gestion des interruptions de threads est possible via les méthodes interrupt() et isInterrupted().
  • La concurrence peut entraîner des problèmes de cohérence, corrigés par la synchronisation avec le mot-clé synchronized.
  • Le multithreading est essentiel dans les applications client/serveur pour gérer plusieurs connexions simultanées.
  • Un serveur multithreadé crée un thread par client pour traiter les requêtes de manière concurrente.

Partager

Commentaires

Aucun commentaire pour le moment. Posez la première question.

Les commentaires sont relus avant publication. Votre e-mail n'est jamais affiché.

← Toutes les révisions