/* * Programme simulant la gestion d'une imprimante * * Paradigme de producteur/consommateur * * Utilisation de sémaphore. * * Ajout MS pour terminaison: theEnd et sem_getValue(). * */ #include #include #include #include #include #include #include #define NOMFICHIERMAX 80 #define NBPOOL 3 #define NBTAMPON 2 /* les zones tampons sont stockees a des endroits differents pour ne pas partager une meme zone entre plusieurs threads */ char tampon[NBTAMPON][NOMFICHIERMAX]; pthread_mutex_t mutex_imprimante; pthread_mutex_t mutex_tampon; int iExtrait = 0; int iDepot = 0; sem_t placeDispo; sem_t infoPrete; /* Booleen indiquant (si egal a 1) que tous les threads consommateurs doivent arreter leur consommation */ int theEnd = 0; void impression(char *nomFic){ pthread_mutex_lock(&mutex_imprimante); printf("Debut d'impression de \"%s\"...\n", nomFic); sleep(3); /* Simule la lenteur de l'impression */ printf("...Fin d'impression de \"%s\"...\n", nomFic); pthread_mutex_unlock(&mutex_imprimante); } void P(sem_t *semaphore) { sem_wait(semaphore); /* sem_wait renvoie toujours 0 */ } void V(sem_t *semaphore) { int retcode; retcode = sem_post(semaphore); if (retcode == -1) { /* errno ERANGE, EBUSY */ perror("sem_post"); exit(EXIT_FAILURE); } } int producteur() { char nomFic[NOMFICHIERMAX]; printf("Nom du fichier a imprimer (taper '0' pour terminer) ? "); scanf("%s", nomFic); if (strcmp(nomFic,"0") == 0) return 0; /* calcul de l'information */ P(&placeDispo); /* depot de l'information */ /* pas de protection avec mutex car un seul producteur * et accès producteur/consommateur proteges avec * semaphore. */ strncpy(tampon[iDepot], nomFic, NOMFICHIERMAX); iDepot = (iDepot + 1) % NBTAMPON ; V(&infoPrete); return 1; } void *consommateur(void *args) { char nomFic[NOMFICHIERMAX]; while (1) { P(&infoPrete); if (theEnd) { break; } /* extraction de l'information */ /* protection entre consommateurs avec mutex */ pthread_mutex_lock(&mutex_tampon); strcpy(nomFic, tampon[iExtrait]); iExtrait = (iExtrait + 1) % NBTAMPON; pthread_mutex_unlock(&mutex_tampon); V(&placeDispo); /* utilisation */ impression(nomFic); } pthread_exit(NULL); } void attenteImpression() { int nbImpressions = 0; int i; int sval; do { if (!producteur()) break; nbImpressions ++; } while (1); /* On attend d'etre sur que tous les threads d'impression ne travaillent plus. */ printf("Debut attente que threads impression aient fini\n"); sem_getvalue(&placeDispo, &sval); while(sval != 0) { P(&placeDispo); sem_getvalue(&placeDispo, &sval); } printf("Fin attente que threads impression aient fini\n"); /* Maintenant qu'on en est sur, on dit a tous les threads de se terminer */ theEnd = 1; for (i = 0; i < NBPOOL ; i++) { V(&infoPrete); } printf("Au revoir: %d demandes d'impressions effectuees\n", nbImpressions); } int main(){ int i; pthread_t threadPool[NBPOOL]; sem_init(&placeDispo, 0, NBTAMPON); sem_init(&infoPrete, 0, 0); pthread_mutex_init(&mutex_imprimante, NULL); pthread_mutex_init(&mutex_tampon, NULL); for (i = 0; i < NBPOOL ; i++) { int retcode; retcode = pthread_create(&(threadPool[i]), NULL, consommateur, NULL); if (retcode != 0) { perror("pthread_create"); exit(EXIT_FAILURE); } } attenteImpression(); for (i = 0; i < NBPOOL; i ++) pthread_join(threadPool[i], NULL); pthread_mutex_destroy(&mutex_imprimante); pthread_mutex_destroy(&mutex_tampon); sem_destroy(&placeDispo); sem_destroy(&infoPrete); return EXIT_SUCCESS; }