/****************************************************************************** ** ** 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 se fait avec des semaphores ** ** © 2002, Éric Renault pour l'Institut National des Télécommunications. ** © 2003, Denis Conan et Michel Simatic ** © 2013, François Trahay. ** ******************************************************************************/ #include #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 /* Structure caracterisant un segment de memoire partage : ecrivain (resp. lecteur) indique le prochain caractere a ecrire (resp. lire) */ typedef struct { sem_t infoPrete; sem_t placeDispo; unsigned int ecrivain; unsigned int lecteur; int caractere[CAR_MAX]; } shm_t ; /* ** Écriture d'un entier. */ void ecrit_entier(shm_t * shm, int entier) { sem_wait(&shm->placeDispo); shm->caractere[POS(shm->ecrivain)] = entier; shm->ecrivain = POS(shm->ecrivain + 1); sem_post(&shm->infoPrete); } /* ** Lecture d'un entier. */ int lit_entier(shm_t* shm) { int c; sem_wait(&shm->infoPrete); c = shm->caractere[POS(shm->lecteur)]; shm->lecteur = POS(shm->lecteur + 1); sem_post(&shm->placeDispo); 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_SEM_DC"); sprintf(key[SHM_CD], "/CLE_SHM_SEM_CD"); sprintf(key[SHM_DL], "/CLE_SHM_SEM_DL"); sprintf(key[SHM_LD], "/CLE_SHM_SEM_LD"); /* Identification et attachement des espaces d'adressage partagés. */ /* Avec initialisation des sémaphores associés à ces espaces */ for(i = 0 ; i < SHM_TOTAL ; i ++) { int retour; id[i] = shm_open(key[i], O_CREAT| O_RDWR, 0666); assert(id[i]>=0); /* set the size of the shared memory segment */ retour = ftruncate(id[i], sizeof(shm_t)); assert(retour >= 0); /* map the shared memory segment in the current address space */ shm[i] = mmap(NULL, sizeof(shm_t), PROT_READ|PROT_WRITE, MAP_SHARED, id[i], 0); assert(shm[i]>=0); retour = sem_init(&shm[i]->infoPrete, 1, 0); assert(retour==0); retour = sem_init(&shm[i]->placeDispo, 1, CAR_MAX); assert(retour==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 = sem_destroy(&shm[i]->infoPrete); assert(retour == 0); retour = sem_destroy(&shm[i]->placeDispo); assert(retour == 0); retour = munmap(shm[i], sizeof(shm_t)); 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); }