1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
|
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <windows.h>
#define psleep(sec) Sleep((sec)*1000)
#if defined(Win32)
#include <windows.h>
#define psleep(sec) Sleep((sec)*1000)
#elif defined(Linux)
#include <unistd.h>
#define psleep(sec)sleep((sec))
#endif
#define STOCK_INITIAL 20
#define NOMBRE_CLIENT 5
/* http://franckh.developpez.com/tutoriels/posix/pthreads/ */
/* Structure stockant les informations des threads clients et du magasin */
typedef struct S_Magasin S_Magasin;
struct S_Magasin
{
int S_Magasin_Fin[NOMBRE_CLIENT];
int S_Magasin_Stock;
pthread_t S_Magasin_Thread_Magasin;
pthread_t S_Magasin_Thread_Client[NOMBRE_CLIENT];
pthread_mutex_t S_Magasin_Mutex_S_Magasin_Stock;
pthread_cond_t S_Magasin_Condition_S_Magasin_Stock;
pthread_cond_t S_Magasin_Condition_Client;
};
static S_Magasin s_magasin=
{
.S_Magasin_Fin=0,
.S_Magasin_Stock=STOCK_INITIAL,
.S_Magasin_Mutex_S_Magasin_Stock=PTHREAD_MUTEX_INITIALIZER,
.S_Magasin_Condition_S_Magasin_Stock=PTHREAD_COND_INITIALIZER,
.S_Magasin_Condition_Client=PTHREAD_COND_INITIALIZER,
};
/* Fonction pour tirer un nombre au sort entre 0 et nombre_maximum */
static int fonction_generer_nombre_aleatoire(int nombre_maximum)
{
double nombre_aleatoire;
nombre_aleatoire=(double)nombre_maximum*rand();
nombre_aleatoire= nombre_aleatoire/(RAND_MAX+1.0);
return((int)nombre_aleatoire);
}
/* Fonction pour le thread du magasin */
/* Le thread attendant que la condition soit remplie pour s'activer, nous n'avons plus besoin du test
à l'intérieur de la boucle, nous pouvons donc directement remplir le stock. Nous pouvons voir un processus
particulier en ce qui concerne les conditions. En effet, si on regarde le début du corps de la boucle,
on peut s'apercevoir que le thread prend le mutex et se met en attente de la condition. En réalité,
le thread relâche le mutex aussitôt et le reprend automatiquement lorsque la condition est vraie
et qu'il soit réveillé par un autre thread. Lorsque la stock est remplit, la fonction le signale au thread
du client courant. */
static void* fonction_magasin(void *p_donnee)
{
while(1)
{
/* Debut de la zone protegee */
pthread_mutex_lock(&s_magasin.S_Magasin_Mutex_S_Magasin_Stock);
pthread_cond_wait(&s_magasin.S_Magasin_Condition_S_Magasin_Stock,&s_magasin.S_Magasin_Mutex_S_Magasin_Stock);
s_magasin.S_Magasin_Stock=STOCK_INITIAL;
printf("Remplissage du stock du magasin de %d articles !\n",s_magasin.S_Magasin_Stock);
pthread_cond_signal(&s_magasin.S_Magasin_Condition_Client);
pthread_mutex_unlock(&s_magasin.S_Magasin_Mutex_S_Magasin_Stock);
/* Fin de la zone protegee. */
}
return NULL;
}
/* Fonction pour les threads des clients */
/* Cette fonction a aussi eu droit à un petit lifting. En effet, un test a été rajouté qui permet
de déterminer si le stock est en quantité suffisante par rapport à la demande du client.
Si ce n'est pas le cas, le thread le signal au thread du magasin qui prend le relais,
le thread appelant ce met en attente le temps que le magasin réalise sa tâche. */
static void* fonction_client(void *p_donnee)
{
int client_nombre_pris_sur_stock=0;
int client_numero=(int)p_donnee;
while(s_magasin.S_Magasin_Fin[client_numero]<3)
{
client_nombre_pris_sur_stock=fonction_generer_nombre_aleatoire(5);
psleep(fonction_generer_nombre_aleatoire(2));
/* Debut de la zone protegee */
pthread_mutex_lock(&s_magasin.S_Magasin_Mutex_S_Magasin_Stock);
if(client_nombre_pris_sur_stock>s_magasin.S_Magasin_Stock)
{
pthread_cond_signal(&s_magasin.S_Magasin_Condition_S_Magasin_Stock);
pthread_cond_wait(&s_magasin.S_Magasin_Condition_Client,&s_magasin.S_Magasin_Mutex_S_Magasin_Stock);
s_magasin.S_Magasin_Fin[client_numero]++;
}
else
{
s_magasin.S_Magasin_Stock-=client_nombre_pris_sur_stock;
printf("Le client => %d, prend %d du stock,reste %d en stock !\n",client_numero,client_nombre_pris_sur_stock,s_magasin.S_Magasin_Stock);
}
pthread_mutex_unlock(&s_magasin.S_Magasin_Mutex_S_Magasin_Stock);
/* Fin de la zone protegee */
}
return NULL;
}
int main(int argc,char *argv[])
{
int i=0;
int thread_magasin_retour=0;
int thread_client_retour=0;
void** pp_thread_magasin_join=NULL;
/* Creation des threads. */
printf("Creation du thread du magasin !\n");
thread_magasin_retour=pthread_create(&s_magasin.S_Magasin_Thread_Magasin,NULL,fonction_magasin,NULL);
/* Creation des threads des clients si celui du magasinn a reussi. */
if(!thread_magasin_retour)
{
printf("Creation des threads clients !\n");
for(i=0;i<NOMBRE_CLIENT;i++)
{
thread_client_retour=pthread_create(&s_magasin.S_Magasin_Thread_Client[i],NULL,fonction_client,(void*)i);
if(thread_client_retour)
{
fprintf(stderr,"%s",strerror(thread_client_retour));
}
}
}
else
{
fprintf(stderr,"%s",strerror(thread_magasin_retour));
}
/* Attente de la fin des threads. */
for(i=0;i<NOMBRE_CLIENT;i++)
{
pthread_join(s_magasin.S_Magasin_Thread_Client[i],NULL);
}
pthread_join(s_magasin.S_Magasin_Thread_Magasin,pp_thread_magasin_join);
pthread_exit(pp_thread_magasin_join);
return EXIT_SUCCESS;
} |
Partager