Synchronisation multicouche avec tampons partagés (INF3600/2610)

Ce document présente un ensemble d'exercices sur la synchronisation de processus concurrents à l'aide de sémaphores et de moniteurs, dans le cadre d'un examen ou d'un devoir en informatique.

D'après le document Synchronisation multicouche avec tampons partagés (INF3600/2610)

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

Document source

Synchronisation multicouche avec tampons partagés (INF3600/2610)

Programming, Math, Synchronization · PDF · 22 pages · 2006

Afficher l'aperçu du document

Consulter le document original →

Ce document présente un ensemble d'exercices sur la synchronisation de processus concurrents à l'aide de sémaphores et de moniteurs, dans le cadre d'un examen ou d'un devoir en informatique. Il teste la compréhension des mécanismes de synchronisation, la gestion des accès aux ressources partagées, la prévention des interblocages, et la capacité à écrire des pseudocodes corrects pour des problèmes classiques de synchronisation.

Exercice 1

On considère un système multicouche avec trois processus P0, P1 et P2, communiquant via deux tampons partagés T0 et T1 de taille N. Il s'agit de synchroniser ces processus pour éviter les conflits d'accès et interblocages.

a) Utilisation des sémaphores pour contrôler l'accès aux tampons

Chaque tampon partagé doit être protégé par un mécanisme d'exclusion mutuelle pour éviter que deux processus n'y accèdent simultanément. On utilise un sémaphore mutex pour chaque tampon, initialisé à 1, garantissant l'exclusion mutuelle.

De plus, pour gérer la production et la consommation des messages dans chaque tampon, on utilise deux sémaphores par tampon :

  • Vide : nombre de cases libres dans le tampon, initialisé à N.
  • Plein : nombre de cases occupées dans le tampon, initialisé à 0.

Ces sémaphores permettent de contrôler que le producteur ne dépose pas dans un tampon plein et que le consommateur ne retire pas d'un tampon vide.

Pour éviter l'interblocage, il faut que les processus respectent un ordre strict d'acquisition des sémaphores et que les opérations P (wait) et V (signal) soient bien placées.

b) Pseudocodes des processus

On note :

  • mutexT0, pleinT0, videT0 pour le tampon T0
  • mutexT1, pleinT1, videT1 pour le tampon T1
Processus P0 {
  while (true) {
    Message m = Lire();          // lire message du clavier
    P(videT0);
    P(mutexT0);
    Deposer(m, T0);
    V(mutexT0);
    V(pleinT0);
  }
}

Processus P1 {
  while (true) {
    P(pleinT0);
    P(mutexT0);
    Message m = Retirer(T0);
    V(mutexT0);
    V(videT0);

    Message mEnc = Encrypter(m);

    P(videT1);
    P(mutexT1);
    Deposer(mEnc, T1);
    V(mutexT1);
    V(pleinT1);
  }
}

Processus P2 {
  while (true) {
    P(pleinT1);
    P(mutexT1);
    Message m = Retirer(T1);
    V(mutexT1);
    V(videT1);
    Envoyer(m);
  }
}

Réponse : Les sémaphores mutex, plein et vide permettent de garantir l'exclusion mutuelle et la synchronisation correcte entre les producteurs et consommateurs sur les tampons T0 et T1.

Exercice 2

1) Effet d'une file LIFO pour un sémaphore

Si la file d'attente d'un sémaphore est gérée selon la discipline LIFO (last in first out), le dernier processus à attendre sera servi en premier. Cela peut entraîner une inversion de priorité et potentiellement une famine pour les processus plus anciens, car les nouveaux entrants peuvent toujours passer avant eux.

2) Avantage des moniteurs sur les sémaphores

Les moniteurs encapsulent la synchronisation et la gestion des variables partagées dans une structure plus sûre et plus simple à utiliser que les sémaphores, qui sont des primitives plus basses. Les moniteurs évitent les erreurs de programmation liées à un mauvais usage des opérations P et V, et facilitent la maintenance et la compréhension du code.

3) Complétion du producteur/consommateur avec sémaphores

Le producteur produit M caractères à la fois (1 ≤ M ≤ N), tandis que le consommateur consomme un caractère à la fois. Les sémaphores Plein, Vide et Mutex sont utilisés pour gérer le tampon circulaire T de taille N.

Producteur {
  int ip = 0, M;
  char ch[N];
  while (true) {
    M = Lire(ch, N);  // lit une chaîne de longueur M
    for (int i = 0; i < M; i++) {
      P(Vide);       // attendre qu'il y ait de la place
    }
    P(Mutex);
    Deposer(ch, M, ip);
    ip = (ip + M) % N;
    V(Mutex);
    for (int i = 0; i < M; i++) {
      V(Plein);      // signaler la disponibilité de M caractères
    }
  }
}

Consommateur {
  int ic = 0;
  char c;
  while (true) {
    P(Plein);
    P(Mutex);
    c = Retirer(ic);
    ic = (ic + 1) % N;
    V(Mutex);
    V(Vide);
    Traiter(c);
  }
}

Réponse : Les sémaphores Plein, Vide et Mutex sont utilisés pour assurer la synchronisation correcte entre producteur et consommateur, même si le producteur produit plusieurs caractères à la fois.

Exercice 3

1) Synchronisation des moines Shaolins

Trois moines ont chacun un bol et une baguette, mais pour manger, ils ont besoin de deux baguettes. Pour éviter l'interblocage, on peut utiliser un seul sémaphore comptant le nombre total de baguettes disponibles (ici 3). Chaque moine attend que deux baguettes soient disponibles avant de manger. Ainsi, on utilise un sémaphore initialisé à 2 (nombre de baguettes nécessaires), et chaque moine effectue P(2) avant de manger et V(2) après.

2) Ordonnanceur pour deux processeurs avec files alternées

Le thread ordonnanceur doit remplir alternativement les deux files d'attente (buffers), chacune pouvant contenir 4 processus. On utilise les sémaphores sem_libre et sem_occupe pour contrôler les cases libres et occupées de chaque buffer.

void *ordonnanceur(void *inutilise) {
  int i[NB_BUFF], buff;
  for (buff = 0; buff < NB_BUFF; buff++) i[buff] = 0;
  buff = 0;
  while (1) {
    P(&sem_libre[buff]);                      // attendre qu'il y ait une place libre dans le buffer courant
    tab[buff][i[buff]] = prochainProc();     // ajouter un processus dans le buffer courant
    V(&sem_occupe[buff]);                     // signaler qu'une case est occupée
    i[buff] = (i[buff] + 1) % BUFF_SIZE;     // avancer l'indice
    buff = (buff + 1) % NB_BUFF;              // passer au buffer suivant
  }
}

Réponse : Le thread ordonnanceur remplit alternativement les deux buffers en respectant leur capacité, sans ajouter de sémaphores ou variables supplémentaires.

Exercice 4

1) Synchronisation des processus P1, P2 et P3

Les processus P1 et P2 doivent exécuter leurs cycles en concurrence, puis P3 doit exécuter un cycle après que P1 et P2 aient tous deux terminé leur cycle. Ensuite, P1 et P2 recommencent un nouveau cycle après que P3 ait terminé.

On peut utiliser trois sémaphores :

  • S12 initialisé à 1, pour synchroniser P1 et P2 (exécution simultanée)
  • S3 initialisé à 0, pour que P3 attende la fin de P1 et P2
  • Un compteur partagé pour compter les terminaisons de P1 et P2
Variables:
Semaphore S12 = 1;  // contrôle l'accès aux cycles de P1 et P2
Semaphore S3 = 0;   // P3 attend que P1 et P2 terminent
int compteur = 0;   // nombre de processus P1/P2 terminés

Processus P1 {
  while (true) {
    P(S12);
    printf("cycle %d de 1", n++);
    P(mutex_compteur);
    compteur++;
    if (compteur == 2) V(S3);
    V(mutex_compteur);
    V(S12);
    // attendre que P3 termine
    P(S3);
    V(S3);
  }
}

Processus P2 identique à P1, avec printf("cycle %d de 2", n++)

Processus P3 {
  while (true) {
    P(S3);
    printf("cycle %d de 3", n++);
    compteur = 0;
    V(S3);
  }
}

Réponse : Les sémaphores permettent de synchroniser les cycles selon les contraintes données.

2) Modélisation de l'intersection routière

Le système modélise une intersection avec 3 voies nord-sud et 2 voies est-ouest, avec des règles spécifiques de feu vert et de flèches. La synchronisation classique utilisée est un exclusion mutuelle stricte entre les phases de feu vert est-ouest, nord-sud et flèche.

On identifie :

  • Un processus léger pour la gestion des feux (synchronisation des phases)
  • Un processus par voie pour gérer les files d'attente des voitures
  • Des sémaphores pour chaque phase de feu (est-ouest, nord-sud, flèche), initialisés à 1 ou 0 selon l'état initial
  • Des mutex pour protéger les files d'attente (listes STL)

Réponse : Le système utilise un modèle de synchronisation par exclusion mutuelle entre phases de feu, avec des sémaphores et mutex pour gérer les files et l'alternance des feux.

Exercice 5

1) Synchronisation de la communication entre deux processus A et B avec un tampon unique

Le tampon T contient un seul message à la fois, utilisé alternativement par A et B. Il faut synchroniser les dépôts et récupérations pour éviter les conflits.

On définit deux sémaphores :

  • sem_depot initialisé à 1 (autorise le dépôt)
  • sem_recup initialisé à 0 (attente de la récupération)
Semaphore sem_depot = 1;
Semaphore sem_recup = 0;
char T[256];

Processus A {
  while (true) {
    lire(mess);
    P(sem_depot);       // attendre que le tampon soit libre pour déposer
    depot(mess);
    V(sem_recup);       // signaler que le message est prêt à être récupéré
    P(sem_depot);       // attendre la réponse
    recuperer(rep);
    V(sem_depot);       // autoriser un nouveau dépôt
  }
}

Processus B {
  while (true) {
    P(sem_recup);       // attendre un message à récupérer
    recuperer(mess);
    reponse(mess, rep);
    depot(rep);
    V(sem_depot);       // signaler que la réponse est déposée
  }
}

Réponse : Les sémaphores sem_depot et sem_recup assurent la synchronisation alternée entre A et B.

2) Ajout d'un troisième processus C communiquant avec B via le même tampon

Le processus B doit pouvoir recevoir des messages de A ou C, et répondre au bon expéditeur. Il faut donc distinguer les sémaphores et tampons pour chaque expéditeur, ou utiliser un mécanisme d'identification des messages.

Comme il n'y a qu'un seul tampon, on peut utiliser deux sémaphores sem_depot_A, sem_depot_C et sem_recup_A, sem_recup_C, chacun initialisé comme précédemment, pour gérer les échanges séparément. B attend sur les deux sémaphores sem_recup_A et sem_recup_C (par exemple en alternance ou avec un mécanisme de priorité).

Réponse : La synchronisation nécessite des sémaphores distincts par expéditeur pour éviter les conflits sur le tampon unique.

Exercice 6

Synchronisation de la fabrication de stylos à bille

Les opérations sont :

  • RC : remplissage de la cartouche
  • BO : assemblage du bouchon arrière et du corps
  • AS : assemblage de la cartouche avec le corps et le capuchon (doit attendre RC et BO)
  • EM : emballage (doit attendre AS)

RC et BO se font en parallèle. AS doit prélever les éléments sur mRC et mBO (opération GP()). EM attend le stock issu d'AS.

On utilise :

  • Un tampon stock de taille N (FIFO) pour stocker les produits AS
  • Des sémaphores Plein, Vide, Mutex pour gérer ce tampon
  • Des barrières ou sémaphores pour synchroniser AS avec RC et BO
mRC() {
  while (true) {
    RC();
    V(sem_RC);    // signaler fin RC
  }
}

mBO() {
  while (true) {
    BO();
    V(sem_BO);    // signaler fin BO
  }
}

mAS() {
  while (true) {
    P(sem_RC);    // attendre RC
    P(sem_BO);    // attendre BO
    GP();         // prélever éléments
    AS();
    P(Vide);
    P(Mutex);
    DeposerProduit();
    V(Mutex);
    V(Plein);
  }
}

mEM() {
  while (true) {
    P(Plein);
    P(Mutex);
    RetirerProduit();
    V(Mutex);
    V(Vide);
    EM();
  }
}

Réponse : Les sémaphores permettent de synchroniser les opérations selon leurs dépendances et de gérer le stock FIFO.

Exercice 7

Contrôle de déplacement de robots sur segments exclusifs

Les segments AB, BC et BD doivent être utilisés par un seul robot à la fois. Deux types de robots : RobotAC (A vers C) traverse AB puis BC, RobotDA (D vers A) traverse BD puis AB.

On utilise un sémaphore par segment, initialisé à 1 :

  • semAB = 1
  • semBC = 1
  • semBD = 1
Processus RobotAC {
  P(semAB);          // 1 - traverser AB
  TraverserSegAB();
  V(semAB);

  P(semBC);          // 2 - traverser BC
  TraverserSegBC();
  V(semBC);
}

Processus RobotDA {
  P(semBD);          // 4 - traverser BD
  TraverserSegBD();
  V(semBD);

  P(semAB);          // 5 - traverser AB
  TraverserSegAB();
  V(semAB);
}

Réponse : L'utilisation de sémaphores par segment garantit l'exclusion mutuelle sur chaque segment, évitant collisions.

Problèmes potentiels : Pas d'interblocage si l'ordre d'acquisition est respecté (RobotAC acquiert AB puis BC, RobotDA acquiert BD puis AB). Cependant, il peut y avoir un risque d'interblocage si RobotAC attend BC et RobotDA attend AB simultanément. Une solution est d'imposer un ordre global d'acquisition des sémaphores.

Exercice 8

a) Compléter les procédures avec sémaphores

On modélise une intersection avec deux voies à sens unique, un feu vert alternant entre voie 1 et voie 2. Une seule voiture peut traverser à la fois.

On définit :

  • Semaphore mutex = 1 pour l'exclusion mutuelle sur l'intersection
  • Semaphore feu1 et feu2 pour indiquer quel feu est vert (initialement feu1 = 1, feu2 = 0)
void Traversee1() {
  P(feu1);       // attendre feu vert voie 1
  P(mutex);      // entrer intersection
  circuler();
  V(mutex);      // libérer intersection
  V(feu2);       // passer feu vert à voie 2
}

void Traversee2() {
  P(feu2);
  P(mutex);
  circuler();
  V(mutex);
  V(feu1);
}

b) Compléter le moniteur

Variables :

  • Feu = 1 ou 2
  • Nbw1, Nbw2 : nombre de voitures sur voie 1 et voie 2
  • Variables de condition pour attendre le feu vert

Le moniteur contrôle les entrées et sorties des voitures, en bloquant celles dont le feu est rouge.

Réponse : Le moniteur utilise des variables de condition pour faire attendre les voitures au feu rouge et les réveiller lorsque le feu passe au vert, garantissant l'exclusion mutuelle sur l'intersection.

Exercice 9

Implémentation d'un compteur d'événements avec sémaphores

Un compteur d'événements E a :

  • val : valeur actuelle
  • Une file d'attente de processus en attente

On ajoute :

  • Semaphore mutex pour exclusion mutuelle
  • Semaphore sem pour bloquer les processus en attente
struct CompteurEvenement {
  int val;
  Semaphore mutex = 1;
  Semaphore sem = 0;
  int attente = 0;  // nombre de processus en attente
};

void Await(CompteurEvenement *E, int Valeur) {
  P(E->mutex);
  if (E->val < Valeur) {
    E->attente++;
    V(E->mutex);
    P(E->sem);       // bloquer le processus
    P(E->mutex);
    E->attente--;
  }
  V(E->mutex);
}

void Advance(CompteurEvenement *E) {
  P(E->mutex);
  E->val++;
  for (int i = 0; i < E->attente; i++) {
    V(E->sem);       // réveiller tous les processus en attente
  }
  V(E->mutex);
}

int Read(CompteurEvenement *E) {
  int v;
  P(E->mutex);
  v = E->val;
  V(E->mutex);
  return v;
}

Réponse : Cette implémentation assure la synchronisation correcte des processus attendant une valeur donnée du compteur.

Exercice 10

Passage à niveau à voie unique

Le contrôleur ferme les barrières lorsqu'un train traverse, et les ouvre s'il n'y a aucun train en attente.

On utilise :

  • Semaphore mutex pour exclusion mutuelle
  • Semaphore train_attente pour compter les trains en attente
  • Semaphore barriere_fermee pour indiquer que la barrière est fermée
Semaphore mutex = 1;
Semaphore train_attente = 0;
Semaphore barriere_fermee = 0;

Contrôleur() {
  while (true) {
    P(train_attente);
    FermerBarrieres();
    V(barriere_fermee);
    // attendre que le train ait traversé
    P(mutex);
    if (PNB(train_attente) == 0) {
      OuvrirBarrieres();
    }
    V(mutex);
  }
}

Train() {
  while (true) {
    P(mutex);
    V(train_attente);     // signaler arrivée
    V(mutex);
    P(barriere_fermee);  // attendre barrière fermée
    Traverser();
    V(barriere_fermee);  // signaler fin traversée
  }
}

Réponse : Les sémaphores assurent la fermeture des barrières avant la traversée et l'ouverture après, en évitant les collisions.

Exercice 11

Vérification de l'implémentation d'échange de cours

Le code verrouille d'abord cours1, désinscrit l'utilisateur, puis teste si cours2 n'est pas plein. Si non plein, il verrouille cours2, inscrit l'utilisateur, puis déverrouille cours2. Enfin, il déverrouille cours1.

Problèmes :

  • Il y a un risque d'interblocage si deux étudiants veulent échanger simultanément entre les mêmes cours dans l'ordre inverse (cours1 puis cours2 et inversement).
  • Le verrouillage n'est pas ordonné, ce qui peut provoquer un deadlock.
  • Si cours2 est plein, l'utilisateur est désinscrit de cours1 sans être inscrit ailleurs, ce qui est incorrect.

Solution :

  • Verrouiller toujours les cours dans un ordre global (par exemple, ordre croissant des identifiants de cours) pour éviter les interblocages.
  • Vérifier la disponibilité de cours2 avant de désinscrire de cours1.
  • Effectuer l'échange de façon atomique, ou abandonner si l'échange n'est pas possible.

Réponse : L'implémentation est incorrecte. Il faut ordonner les verrous et vérifier la disponibilité avant désinscription pour éviter perte de cours et interblocage.

Exercice 12

a) Implémentation des barrières avec sémaphores

Une barrière synchronise n processus, bloquant chacun jusqu'à ce que tous atteignent la barrière.

class Barrier_t {
  int count = 0;
  int n;                  // nombre de processus
  Semaphore mutex = 1;
  Semaphore turnstile = 0;

  Barrier_t(int nb) {
    n = nb;
  }

  void Barriere() {
    P(mutex);
    count++;
    if (count == n) {
      for (int i = 0; i < n; i++) {
        V(turnstile);
      }
      count = 0;
    }
    V(mutex);
    P(turnstile);
  }
}

b) Synchronisation de la chaîne de production de stylos

On utilise deux barrières :

  • barriere1 pour synchroniser la fin des opérations RC et BO
  • barriere2 pour synchroniser avant AS et EM
mRC() {
  while (true) {
    RC();
    barriere1.Barriere();
  }
}

mBO() {
  while (true) {
    BO();
    barriere1.Barriere();
  }
}

mAS() {
  while (true) {
    barriere1.Barriere();
    GP();
    AS();
    barriere2.Barriere();
  }
}

mEM() {
  while (true) {
    barriere2.Barriere();
    GP();
    EM();
  }
}

c) Risque d'interblocage avec mauvaise utilisation des barrières

Une mauvaise utilisation des barrières, par exemple un nombre incorrect de processus attendus ou un ordre d'appel incohérent, peut bloquer tous les processus à la barrière, provoquant un interblocage.

Réponse : Oui, un usage incorrect des barrières peut entraîner un interblocage.

Exercice 13

1) Analyse du code avec mutex1 et mutex2

Le processus p1 acquiert mutex1 puis mutex2, modifie n et out, puis libère mutex2 puis mutex1.

Le processus p2 acquiert mutex2, modifie out, puis libère mutex2.

Le processus p3 acquiert mutex1, modifie n, puis libère mutex1.

Problème :

  • Il y a un risque d'interblocage car p1 attend mutex1 puis mutex2, tandis que p2 attend mutex2 seul. Si p2 détient mutex2 pendant que p1 détient mutex1, p1 attend mutex2 et p2 attend mutex1 indirectement, causant un deadlock.
  • La condition d'exclusion mutuelle n'est pas garantie car p3 modifie n sans coordination avec p1.

Solution :

  • Utiliser un seul mutex pour protéger n et out.
  • Ou imposer un ordre strict d'acquisition des mutex.

2) Produit de matrices en parallèle

On crée m threads, chacun calculant un groupe de lignes de la matrice résultat R.

Semaphore mutex = 1;  // pour protéger l'écriture dans R si nécessaire

void CalculLignes(int debut, int fin) {
  for (int i = debut; i < fin; i++) {
    for (int j = 0; j < n; j++) {
      R[i][j] = 0;
      for (int k = 0; k < n; k++) {
        R[i][j] += A[i][k] * B[k][j];
      }
    }
  }
}

Réponse : Chaque thread calcule ses lignes sans conflit, donc mutex n'est pas nécessaire si R est segmenté par lignes.

Exercice 14

1) Modèle correspondant

Le problème des trains sur une voie unique correspond au modèle des philosophes ou lecteurs/rédacteurs, où l'accès exclusif est requis pour la voie, et les trains doivent circuler dans un seul sens à la fois.

2) Code avec sémaphores pour accès et sortie

Semaphore mutex = 1;
Semaphore voieLibre = 1;
int direction = 0;       // 0 = libre, 1 = A vers B, 2 = B vers A
int nbTrains = 0;

void DemandeAccesAversB() {
  P(mutex);
  while (direction == 2) {
    V(mutex);
    P(voieLibre);
    P(mutex);
  }
  direction = 1;
  nbTrains++;
  V(mutex);
}

void SortieAversB() {
  P(mutex);
  nbTrains--;
  if (nbTrains == 0) {
    direction = 0;
    V(voieLibre);
  }
  V(mutex);
}

void DemandeAccesBversA() {
  P(mutex);
  while (direction == 1) {
    V(mutex);
    P(voieLibre);
    P(mutex);
  }
  direction = 2;
  nbTrains++;
  V(mutex);
}

void SortieBversA() {
  P(mutex);
  nbTrains--;
  if (nbTrains == 0) {
    direction = 0;
    V(voieLibre);
  }
  V(mutex);
}

Réponse : Ce code garantit qu'à un instant donné, la voie est utilisée par des trains dans un seul sens, évitant collisions.

Exercice 15

1) Producteurs et consommateurs multiples avec un tampon unique

Pour n producteurs, n consommateurs et un tampon de taille Max :

Semaphore Mutex = 1, Vide = Max, Plein = 0;
Message tampon[Max];
int ip = 0, ic = 0;

Producteur() {
  while (true) {
    Message m = creermessage();
    P(Vide);
    P(Mutex);
    tampon[ip] = m;
    ip = (ip + 1) % Max;
    V(Mutex);
    V(Plein);
  }
}

Consommateur() {
  while (true) {
    P(Plein);
    P(Mutex);
    Message m = tampon[ic];
    ic = (ic + 1) % Max;
    V(Mutex);
    V(Vide);
  }
}

2) Un producteur, n consommateurs et n tampons

Le producteur dépose chaque message dans tous les tampons en commençant par le premier. Chaque consommateur i récupère dans le tampon i.

On utilise un tableau de sémaphores Mutex[i], Vide[i], Plein[i] pour chaque tampon i.

for (int i = 0; i < n; i++) {
  Semaphore Mutex[i] = 1, Vide[i] = Max, Plein[i] = 0;
  Message tampon[i][Max];
  int ip[i] = 0, ic[i] = 0;
}

Producteur() {
  while (true) {
    Message m = creermessage();
    for (int i = 0; i < n; i++) {
      P(Vide[i]);
      P(Mutex[i]);
      tampon[i][ip[i]] = m;
      ip[i] = (ip[i] + 1) % Max;
      V(Mutex[i]);
      V(Plein[i]);
    }
  }
}

Consommateur(int i) {
  while (true) {
    P(Plein[i]);
    P(Mutex[i]);
    Message m = tampon[i][ic[i]];
    ic[i] = (ic[i] + 1) % Max;
    V(Mutex[i]);
    V(Vide[i]);
  }
}

Réponse : Cette adaptation permet au producteur de déposer dans tous les tampons et aux consommateurs de récupérer dans leur tampon respectif.

Méthode

Ce devoir récompense une bonne compréhension des mécanismes fondamentaux de synchronisation : sémaphores, exclusion mutuelle, files d'attente, et moniteurs. Il est essentiel de :

  • Respecter les conventions et notations données dans l'énoncé.
  • Présenter clairement les sémaphores utilisés, leurs valeurs initiales et leur rôle.
  • Montrer les étapes de raisonnement, notamment l'ordre d'acquisition des sémaphores pour éviter interblocages.
  • Éviter les erreurs classiques comme la famine, l'interblocage, ou la mauvaise gestion des files d'attente.
  • Utiliser des pseudocodes précis, avec les opérations P (wait) et V (signal) bien placées.
  • Ne pas inventer d'informations absentes du sujet, et signaler les questions impossibles à traiter.

Les erreurs pénalisées sont notamment :

  • Oublier l'exclusion mutuelle sur les ressources partagées.
  • Ne pas gérer correctement les conditions de synchronisation (tampons pleins/vides).
  • Introduire des variables ou sémaphores non autorisés.
  • Ignorer les risques d'interblocage ou de famine.
  • Ne pas justifier les choix de synchronisation.

Une bonne réponse montre un équilibre entre rigueur formelle, clarté du raisonnement et respect des contraintes imposées.

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