TP 2 - Synchronisation de Threads

Ce TP porte sur la synchronisation de threads en programmation concurrente. Il comporte deux exercices : le premier modélise un scénario de gestion d’une salle de TP avec un nombre limité de places, et le second simule la gestion concurrente d’un compte bancaire avec dépôts et retraits synchronisés.

D'après le document TP 2 - Synchronisation de Threads

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

TP 2 - Synchronisation de Threads

Document source

TP 2 - Synchronisation de Threads

Systèmes d’exploitation & Programmation Concurrente · DOCX · 8 pages · 2014

Consulter le document original →

Ce TP porte sur la synchronisation de threads en programmation concurrente. Il comporte deux exercices : le premier modélise un scénario de gestion d’une salle de TP avec un nombre limité de places, et le second simule la gestion concurrente d’un compte bancaire avec dépôts et retraits synchronisés. Ce TP permet d’apprendre à utiliser les sémaphores, mutex et variables conditionnelles pour coordonner plusieurs threads. Il nécessite un environnement de programmation supportant pthreads et les sémaphores POSIX.

Objectifs

  • Comprendre et mettre en œuvre la synchronisation entre threads à l’aide de sémaphores et mutex.
  • Modéliser un problème réel de gestion de ressources limitées avec des threads.
  • Utiliser les variables conditionnelles pour gérer l’attente et la notification entre threads.
  • Écrire un code multithreadé correct évitant les conditions de course et les blocages.

Prérequis et configuration

  • Connaissance des concepts de base des threads, mutex, sémaphores et variables conditionnelles.
  • Environnement de développement avec support POSIX threads (pthreads) et sémaphores POSIX.
  • Compilateur C compatible pthreads (gcc recommandé).
  • Fonctions externes supposées définies : ouvrir_porte(), fermer_porte(), enseigner() pour l’exercice 1.

Exercice 1 : Synchronisation d’accès à une salle de TP

Dans cet exercice, 80 étudiants doivent suivre une séance de rattrapage dans une salle pouvant accueillir 10 étudiants à la fois. L’enseignant ouvre la porte, attend que la salle soit pleine, ferme la porte, donne la séance, puis ouvre la porte pour laisser sortir les étudiants. Ce cycle se répète jusqu’à ce que tous les étudiants aient assisté à la séance.

Le programme modélise ce scénario avec 1 thread enseignant et 80 threads étudiants. Le thread enseignant est entièrement fourni et utilise plusieurs sémaphores pour contrôler l’entrée et la sortie des étudiants. La tâche consiste à compléter la fonction thread_etudiant() pour que chaque étudiant respecte la synchronisation imposée.

Procédure

Complétez la fonction thread_etudiant(void *arg) en suivant ces étapes :

void *thread_etudiant(void *arg){
  P(&entrer_file); /* Attendre une place disponible dans la salle */

  /* Entrer dans la salle */
  P(&mutex2); /* Protection de la variable etudiants_entrant */
  etudiants_entrant += 1;
  if (etudiants_entrant == CLASS) {
    V(&tous_entres); /* Le dernier étudiant signale que la salle est pleine */
    etudiants_entrant = 0;
  }
  V(&mutex2); /* Libérer la protection */

  P(&sortir_file); /* Attendre l’autorisation de sortir */

  /* Sortir de la salle */
  P(&mutex3); /* Protection de la variable etudiants_sortant */
  etudiants_sortant += 1;
  if (etudiants_sortant == CLASS) {
    V(&tous_sortis); /* Le dernier étudiant signale que la salle est vide */
    etudiants_sortant = 0;
  }
  V(&mutex3); /* Libérer la protection */

  return NULL;
}

Cette implémentation utilise les sémaphores pour gérer l’accès à la salle et la synchronisation avec le thread enseignant. Chaque étudiant attend une place libre, entre, signale s’il est le dernier à entrer, attend l’autorisation de sortir, puis signale s’il est le dernier à sortir.

Exercice 2 : Gestion concurrente d’un compte bancaire

Ce second exercice simule un compte bancaire partagé entre plusieurs threads effectuant des dépôts et des retraits. La synchronisation est nécessaire pour assurer l’exclusion mutuelle lors des mises à jour du solde et pour bloquer les retraits lorsque le solde est insuffisant.

Procédure

1. Déclarez une variable globale int compte = 0;, un mutex pthread_mutex_t m; et une variable conditionnelle pthread_cond_t depot;.

2. Créez 3 threads de dépôt et 4 threads de retrait, chacun exécutant respectivement les fonctions deposit() et withdraw().

3. Implémentez la fonction deposit() ainsi :

void *deposit(void *threadid) {
  int dep;
  long tid = (long) threadid;

  while (1) {
    dep = rand() % (200 - 1) + 1; /* Dépôt entre 1$ et 200$ */

    pthread_mutex_lock(&m);
    compte += dep;
    printf("thread %ld deposits %d \n", tid, dep);
    pthread_mutex_unlock(&m);

    pthread_cond_signal(&depot); /* Signaler aux retraits en attente */

    sleep(1); /* Pause d’environ 1 milliseconde */
  }
}

4. Implémentez la fonction withdraw() ainsi :

void *withdraw(void *threadid) {
  long tid = (long) threadid;
  int ret;

  while (1) {
    ret = rand() % (50 - 1) + 1; /* Retrait entre 1$ et 50$ */

    pthread_mutex_lock(&m);
    while (ret > compte) {
      printf("thread %ld – Blocked – Insufficient Funds\n", tid);
      pthread_cond_wait(&depot, &m); /* Attente d’un dépôt */
    }
    compte -= ret;
    printf("thread %ld withdraws %d \n", tid, ret);
    pthread_mutex_unlock(&m);

    sched_yield(); /* Céder le CPU à un autre thread */
  }
}

5. Dans main(), créez et lancez les threads, puis attendez leur terminaison avec pthread_join().

Résultats attendus

  • Exercice 1 : Les étudiants entrent par groupes de 10, la séance démarre uniquement lorsque la salle est pleine, puis les étudiants sortent ensemble. Le programme affiche "C’est tout." à la fin.
  • Exercice 2 : Les dépôts et retraits s’exécutent simultanément. Les retraits bloquent lorsque le solde est insuffisant et reprennent après un dépôt. La sortie affiche les opérations effectuées par chaque thread, ainsi que les blocages éventuels.

Pièges courants

  • Ne pas protéger correctement les variables partagées etudiants_entrant et etudiants_sortant avec les mutex, ce qui peut causer des conditions de course.
  • Oublier de signaler les sémaphores tous_entres ou tous_sortis, bloquant ainsi le thread enseignant.
  • Dans l’exercice 2, ne pas utiliser la variable conditionnelle pour bloquer les retraits lorsque le solde est insuffisant, ce qui peut entraîner des retraits négatifs.
  • Ne pas céder le CPU dans les threads de retrait, ce qui peut provoquer une famine d’autres threads.
  • Ne pas initialiser correctement les sémaphores et mutex avant leur utilisation.

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