Cours de Systèmes d'exploitation avancé

TDTP3 -- IPC

A.B.Dragut et V. Risch
Vous êtes priés de rendre en fin de TP par mail:
  1. un log avec vos commandes pour chaque point des exercices à faire et
  2. une archive .tar.gz avec vos codes source.

Exo 01. Introduction synchronisation

Dans cet exercice

vous implémentez un très petit exemple pour voir comment cela fonctionne effectivement. Cet exemple crée un sémaphore, se duplique, et chacun des processus manipule le sémaphore (P() et V()). Le père attend ensuite le fils, et détruit ensuite le sémaphore.

Quoi de neuf :


Travail à faire

Exo 02. Synchronisation et mémoire partagée

Dans cet exercice

vous rajoutez de sémaphores à l'exercice 5 du TP précédent, qui portait sur la mémoire partagéee.

Quoi de neuf :

Il s'agit d'un couple producteur-consommateur, et l'algorithme de synchronisation et exclusion mutuelle à mettre en place ici est celui à deux sémaphores, "croisés" : Ceci sera mis en oeuvre pour un cadre simple, où le producteur écrit les nombres de 10 à 0 un par un dans la mémoire partagée, et le consommateur les lit et les affiche.
Travail à faire

Exo 03. Signaux, mémoire partagée et synchronisation

Dans cet exercice

on met "le tout" en oeuvre pour simuler un cadre complexe, avec des attentes pour des services, et plusieurs processus, de plusieurs types et dans plusieurs états possibles, et avec de la communication par "tous les moyens".

L'histoire

La modélisation

Chaque client et chaque coiffeur est représenté par un processus. Ces processus sont tous issus d'un main() initial, et exécutent le code d'une fonction client(), respectivement coiffeur(). Ces processus
Travail à faire
  • Copiez le répertoire exo_02 avec le nom exo_03
  • Changez le nom du fichier exo_02.cxx (de diripc) en exo_03.cxx
  • Dans le fichier exo_03.cxx, mettez ces déclarations
  • enum EtatCoiffeur  { ATTENTE, TRAVAIL } ;
    enum EtatClient { AUCUN, DEBOUT, ASSIS, COIFF, SORTANT, FIN } ;
    
    struct memCommStruct {
        int NbrClientsDebout;
        int NbrClientsAssis;
        int NbrCoiffeursAttente;
        int NbrClientsSortant;
        EtatCoiffeur *etatCoiffeur; 
        int *clientDuCoiffeur;
        pid_t *pidCoiffeur;
        EtatClient *etatClient;
        int *coiffeurDuClient;
        pid_t *pidClient;
    };
    
    void SigDfl(int NumSig) {
        if(NumSig != SIGUSR1) {
    	cerr << "Signal " << NumSig << " recu en plein...\n";
    	exit(3);
        }
    }
    
  • Laissez dans le main() seulement le try .. catch() de la structure principale, et
  • Finissez d'écrire la fonction
    void initMem(memCommStruct * memComm, 
    	     int NombreTotalClients, int NombreCoiffeurs) {
    
    qui initialise tous les membres de la memCommStruct pointée par memComm, sachant donc que memComm pointe au début de la zone mémoire, complétant ainsi ceci :
    void initMem(memCommStruct * memComm, 
    	     int NombreTotalClients, int NombreCoiffeurs) {
        const char * offSet (((char *)memComm) + sizeof(memCommStruct));
        memComm -> NbrClientsAssis = 0;
        memComm -> NbrClientsDebout = 0;
        memComm -> NbrCoiffeursAttente = 0;
        memComm -> NbrClientsSortant = 0;
        memComm -> etatCoiffeur = (EtatCoiffeur *)(offSet + 3*sizeof(int));
        // ..... a vous de tout completer 
    }
    
  • Complétez ces fonctions
  • void dumpMem(memCommStruct * memComm, 
    	     int NombreTotalClients, int NombreCoiffeurs) {
        // affiche effectivement le contenu des champs de memComm, et de toutes
        // les cases des tableaux de memComm,
        cerr << "\n";
    }
    	
    void inspecteur(memCommStruct * memComm, CSemBase &loquet, 
    	     int nombreTotalClients, int nombreCoiffeurs) {
    // afficher le contenu des champs de  memComm, et de toutes les cases des
    // tableaux de memComm, en appelant dumpMem()
    }
    
  • Rédigez très soigneusement les diagrammes des états du coiffeur et du client, avec leurs intéractions (envoi de signal, etc.), suivant la description de l'"histoire" racontée ci-haut. Attention, l'attente de signal devra se faire utilisant le blocage suivi de sigsuspend(). Pourquoi?
  • Écrivez les fonctions coiffeur() et client() selon ces diagrammes (et avec les bons paramètres). N'oubliez bien entendu pas d'utiliser le sémaphore pour assurer l'exclusion mutuelle lors des accès en lecture ou écriture à la mémoire partagé, tout en y faisant bien attention.
  • Compilez et testez