Outils personnels
Vous êtes ici : Accueil C & C++ Programmation système Les threads Solution 3

Solution 3

Par Benjamin Poulain - Dernière modification 18/04/2008 22:40

Énoncé

Écrire un programme multithread qui simule une file d'attente devant plusieurs guichets. Les personnes dans la file seront représentées par des threads. Quand une personne accédera à un guichet, le thread affichera un message indiquant le numéro de la personne puis se mettra en sommeil entre une et 10 secondes avant d'afficher un message indiquant que la personne a quitté le guichet, puis se terminera. Au départ, il n'y aura aucun guichet ouvert. Le thread principal exécutera une boucle infinie dans laquelle il ajoutera ou supprimera des guichets de sorte qu'il y ait un guichet par tranche de 10 personnes dans la file. Il créera ensuite un nouveau thread correspondant à l'arrivée d'une personne, affichera le nombre de personnes dans la file et le nombre de guichets, puis se mettra en sommeil un nombre aléatoire de secondes compris entre 1 et 5. On considérera que la file est composée des personnes en attente et des personnes aux guichets.

Solution

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <pthread.h>
#include <semaphore.h>

#define DELAI_ARRIVEE_MAX 4
#define DUREE_SERVICE_MAX 20

int nb_guichets = 0;
sem_t sem_guichets;
pthread_mutex_t mutex_file = PTHREAD_MUTEX_INITIALIZER;
int long_file = 0;

void *thread_personne(void *arg)
{
int no_personne = (int)arg;

sem_wait(&sem_guichets);

printf("Personne %d, accès à un guichet.\n", no_personne);

sleep(rand() % DUREE_SERVICE_MAX + 1);

pthread_mutex_lock(&mutex_file);

long_file--;
if ( (long_file + 9) / 10 < nb_guichets )
nb_guichets--;
else
sem_post(&sem_guichets);

printf("Personne %d, fin de service. Longueur file: %d."
" Nombre guichets: %d.\n", no_personne, long_file, nb_guichets);

pthread_mutex_unlock(&mutex_file);

return NULL;
}

int main()
{
srand((unsigned int)time(NULL));

int no_pers = 0;

pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

sem_init(&sem_guichets, 0, nb_guichets);
for ( ; ; )
{
pthread_mutex_lock(&mutex_file);
no_pers++;
long_file++;

if ( (long_file + 9) / 10 > nb_guichets )
{
nb_guichets++;
sem_post(&sem_guichets);
}

//Ne pas permuter le printf suivant avec la création du thread
//sinon le message "Accès à un guichet" peut s'imprimer
//avant le message "Entrée de la personne". Si on veut permuter
//pour gérer plus élégamment l'erreur de création du thread,
//il faut un mutex pour empêcher la fonction de thread de commencer
//avant l'affichage du message d'arrivée de la personne.
printf("Entrée de la personne %d. Longueur file: %d."
" Nombre guichets: %d.\n", no_pers, long_file, nb_guichets);

pthread_t t;
if ( pthread_create(&t, &attr, thread_personne, (void *)no_pers) )
{
perror("pthread_create");
printf("Erreur création personne %d."
" Longueur file: %d. Nombre guichets: %d.\n", no_pers,
long_file, nb_guichets);
long_file--;
}

pthread_mutex_unlock(&mutex_file);
sleep(rand() % DELAI_ARRIVEE_MAX + 1);
}

return EXIT_FAILURE;
}

Remarques.

L'expression (long_file + 9) / 10 donne le nombre de guichets qui devraient exister en fonction de la longueur de la file: pour long_file entre 1 et 10, 1 guichet, entre 11 et et 20, 2 guichets, ...

La supression d'un guichet (obtenue en n'incrémentant pas le sémaphore) lorsqu'une personne sort de la file, ne pouvait s'effectuer dans le thread principal comme c'est le cas pour la création d'un nouveau guichet (réalisée par l'incrémentation du sémaphore). En effet, dans le thread principal, on aurait dû décrémenter le sémaphore par un appel à sem_wait(), si tous les guichets avaient été occupés au moment de l'appel, le thread principal aurait au moins dû attendre la sortie d'une personne et rien n'aurait garanti que le sémaphore libéré n'aurait pas été attribué à un autre thread correspondant à une personne en attente dans la file, obligeant le thread principal à prolonger son attente. Dans le pire des cas, le thread principal aurait dû attendre que la file se vide avant de reprendre son exécution.

Actions sur le document