/****************************************************************************** ** ** Utilisation de segments de mémoire partagés. ** ------------------------------------------- ** Ce programme se compose de trois processus et d'une file de messages. Le ** processus parent est chargé de lire les caractères en provenance de l'entrée ** standard, d'envoyer les chiffres au premier enfant (en utilisant le premier ** espace de mémoire partagé) et les lettres au second (en utilisant le ** troisième espace de mémoire partagé). Une fois la fin de fichier atteinte, ** les enfants renvoient leurs résultats au parent (en utilisant respectivement ** les deuxième et quatrième espaces de mémoire partagés). Le parent affiche ** ensuite les résultats. La synchronisation est sans semaphore, c'est donc ** de l'attente active. ** ** © 2002, Éric Renault pour l'Institut National des Télécommunications. ** © 2003, Denis Conan ** © 2013, François Trahay. ** ******************************************************************************/ #include #include #include #include #include #include #include #include #include #define CAR_MAX 12 #define POS(X) ((X) % CAR_MAX) #define SHM_DC 0 #define SHM_CD 1 #define SHM_DL 2 #define SHM_LD 3 #define SHM_TOTAL 4 #define SHM_SIZE sizeof(shm_t) /* Structure caracterisant un segment de memoire partage : ecrivain (resp. lecteur) indique le prochain caractere a ecrire (resp. lire) */ typedef struct { unsigned int ecrivain; unsigned int lecteur; int caractere[CAR_MAX]; } shm_t ; /* ** Écriture d'un entier. */ void ecrit_entier(shm_t * shm, int entier) { /* Garantie que l'ecrivain n'ecrit pas dans une zone que le lecteur n'a pas encore lue */ /* Synchronisation = attente active */ while(POS(shm -> ecrivain + 1) == POS(shm -> lecteur)) { } shm->caractere[POS(shm->ecrivain)] = entier; shm->ecrivain = POS(shm->ecrivain + 1); } /* ** Lecture d'un entier. */ int lit_entier(shm_t* shm) { int c; /* Garantie que le lecteur ne lit un caractere que si l'ecrivain l'a effectivement ecrit */ /* Synchronisation = attente active */ while(POS(shm->lecteur) == POS(shm->ecrivain)) { } c = shm->caractere[POS(shm->lecteur)]; shm->lecteur = POS(shm->lecteur + 1); return c; } /* ** Somme des chiffres. */ void chiffre(shm_t* lit, shm_t* ecrit) { int car, somme=0; /* Lecture des chiffres et somme. */ while((car = lit_entier(lit)) != EOF) { somme += (car - '0'); } /* Renvoi du résultat. */ ecrit_entier(ecrit, somme); } /* ** Fréquence des lettres. */ void lettre(shm_t* lit, shm_t* ecrit) { int car, frequence['z' - 'a' + 1], i; /* Initialisation. */ for(i = 'a' ; i <= 'z' ; i ++) { frequence[i - 'a'] = 0; } /* Lecture des lettres et incrément des fréquences. */ while((car = lit_entier(lit)) != EOF) { frequence[tolower(car) - 'a']++; } /* Renvoi du résultat. */ for(i = 'a' ; i <= 'z' ; i ++) { ecrit_entier(ecrit, frequence[i - 'a']); } } /* ** Distribution des caractères et affichage des résultats. */ void distributeur(shm_t* ecrit_c, shm_t* lit_c, shm_t* ecrit_l, shm_t* lit_l) { int car, i; /* Distribution des caractères. */ do { car = getchar(); if (isalpha(car) || (car == EOF)) { ecrit_entier(ecrit_l, car); } if (isdigit(car) || (car == EOF)) { ecrit_entier(ecrit_c, car); } } while(car != EOF); /* Lecture et affichage de la somme. */ printf("Somme : %d", lit_entier(lit_c)); /* Lecture et affichage des frequences. */ for(i = 'a' ; i <= 'z' ; i ++) { printf(" ; %c : %d", i, lit_entier(lit_l)); } printf("\n"); } /* ** Mise en place des segments de mémoire partagés et des processus. */ int main(int argc, char* argv[]) { int i, id[SHM_TOTAL], retour; pid_t enfant; shm_t* shm[SHM_TOTAL]; char key[SHM_TOTAL][80]; sprintf(key[SHM_DC], "/CLE_SHM_DC"); sprintf(key[SHM_CD], "/CLE_SHM_CD"); sprintf(key[SHM_DL], "/CLE_SHM_DL"); sprintf(key[SHM_LD], "/CLE_SHM_LD"); /* Identification et attachement des espaces d'adressage partagés. */ /* open the shared memory segment */ for(i=0; i=0); /* set the size of the shared memory segment */ assert(ftruncate(id[i], SHM_SIZE) >= 0); /* map the shared memory segment in the current address space */ shm[i] = mmap(NULL, SHM_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, id[i], 0); assert(shm[i]>=0); } /* Création des enfants et lancement des taches associées. */ switch(enfant = fork()) { case -1 : exit(1); case 0 : chiffre(shm[SHM_DC], shm[SHM_CD]); break ; default : switch(enfant = fork()) { case -1 : exit(2); case 0 : lettre(shm[SHM_DL], shm[SHM_LD]); break ; default : distributeur(shm[SHM_DC], shm[SHM_CD], shm[SHM_DL], shm[SHM_LD]); } } /* Détachement des espaces d'adressage partagés. */ for(i = 0 ; i < SHM_TOTAL ; i ++) { retour = munmap(shm[i], SHM_SIZE); assert(retour >= 0); retour = close(id[i]); assert(retour == 0); if (enfant) { /* Suppression par le parent */ retour = shm_unlink(key[i]); assert(retour >= 0); } } /* Tout s'est bien terminé. */ exit(0); }