/* * Programme simulant la gestion d'une imprimante * * Paradigme de producteur/consommateur * * Utilisation de conditions. * * Prise en compte idee MS pour terminaison (theEnd, ...) * */ #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]; /* mutex_imprimante protege les acces a l'imprimante */ pthread_mutex_t mutex_imprimante; /* mutex_condition protege - cond_infoPrete (wait et signal) - cond_placeDispo (wait et signal) - iExtrait, iDepot - infoPrete - theEnd - nbImpressionsTraitees */ pthread_mutex_t mutex_condition; pthread_mutex_t mutex_compteur; int iExtrait = 0; int iDepot = 0; /* autant de booleen infoPrete que de zones tampons */ int infoPrete[NBTAMPON]; pthread_cond_t cond_infoPrete; pthread_cond_t cond_placeDispo; /* * Terminaison: * * Booleen indiquant (si egal a 1) que tous les threads consommateurs * doivent arreter leur consommation * * Compteur impressions traitees */ int theEnd = 0; int nbImpressionsTraitees = 0; void impression(char *nomFic){ pthread_mutex_lock(&mutex_imprimante); printf("Debut d'impression de \"%s\"...\n", nomFic); sleep(1); /* Simule la lenteur de l'impression */ printf("...Fin d'impression de \"%s\"...\n", nomFic); pthread_mutex_unlock(&mutex_imprimante); } int producteur() { char nomFic[NOMFICHIERMAX]; /* calcul de l'information */ printf("Nom du fichier a imprimer (taper '0' pour terminer) ? "); scanf("%s", nomFic); if (strcmp(nomFic,"0") == 0){ infoPrete[iDepot] = 1; pthread_cond_signal(&cond_infoPrete); return 0; } /* Cas d'un nom de fichier */ /* P(placeDispo) */ pthread_mutex_lock(&mutex_condition); /* la boucle permet de garantir que la condition est remplie pour passer a la suite */ while (infoPrete[iDepot]) pthread_cond_wait(&cond_placeDispo, &mutex_condition); /* depot de l'information */ strncpy(tampon[iDepot],nomFic,NOMFICHIERMAX); infoPrete[iDepot] = 1; iDepot = (iDepot + 1) % NBTAMPON ; nbImpressionsTraitees ++; /* V(infoPrete) */ pthread_cond_signal(&cond_infoPrete); pthread_mutex_unlock(&mutex_condition); return 1; } void *consommateur(void *args) { char nomFic[NOMFICHIERMAX]; while (1) { /* P(infoPrete) */ pthread_mutex_lock( &mutex_condition); /* la boucle permet de garantir que la condition est remplie pour passer a la suite */ while (!infoPrete[iExtrait]) pthread_cond_wait(&cond_infoPrete, &mutex_condition); if (theEnd) { /* Dans certains cas, le mutex n'est pas verrouille */ infoPrete[iExtrait] = 1; pthread_cond_signal(&cond_placeDispo); pthread_mutex_unlock( &mutex_condition); break; } /* extraction de l'information */ strcpy(nomFic, tampon[iExtrait]); infoPrete[iExtrait] = 0; iExtrait = (iExtrait + 1) % NBTAMPON; /* V(placeDispo) */ pthread_cond_signal(&cond_placeDispo); pthread_mutex_unlock(&mutex_condition); /* l'impression apres la recuperation du fichier a imprimer et la liberation de la place dans la zone tampon permet a un autre thread de commencer a travailler en utilisant la meme zone alors que ce thread est en train d'imprimer. L'attente se fera au niveau de l'imprimante */ /* utilisation */ impression(nomFic); } pthread_exit(NULL); } void attenteImpression() { int nbImpressionsDemandees = 0; do { if (!producteur()) break; nbImpressionsDemandees ++; } 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"); while (nbImpressionsTraitees < nbImpressionsDemandees) { pthread_mutex_lock(&mutex_condition); pthread_cond_wait(&cond_placeDispo, &mutex_condition); pthread_mutex_unlock(&mutex_condition); } 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; pthread_mutex_lock(&mutex_condition); pthread_cond_broadcast(&cond_infoPrete); pthread_mutex_unlock(&mutex_condition); printf("Au revoir: %d demandes d'impressions effectuees\n", nbImpressionsDemandees); } int main(){ int i; pthread_t threadPool[NBPOOL]; pthread_cond_init(&cond_placeDispo, NULL); pthread_cond_init(&cond_infoPrete, NULL); pthread_mutex_init(&mutex_imprimante, NULL); pthread_mutex_init(&mutex_condition, NULL); pthread_mutex_init(&mutex_compteur, NULL); for (i = 0; i < NBTAMPON ; i++) infoPrete[i] = 0; 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_condition); pthread_mutex_destroy(&mutex_compteur); pthread_cond_destroy(&cond_placeDispo); pthread_cond_destroy(&cond_infoPrete); return EXIT_SUCCESS; }