La versione più recente è stata modificata il 2006-06-08 20:42:48 da DenteDiLupo [aggiunto link alla pagina principale]
Aggiunzioni:
Torna a Lab Sistemi Operativi
La versione più vecchia di questa pagina è stata modificata il 2006-06-08 20:12:32 da GiPPe []
Vista della pagina:
Come ultima fatica prima degli esami ho risolto il problema dei pizzaioli in UNIX. Ho aggiunto qualcosa per rendere visibile l'utilizzo dei mutex.
Il testo del problema:
In una pizzeria molto frequentata vi lavorono due pizzaioli. L’unico forno disponibile può contenere un massimo di 8 pizze quindi i pizzaioli devono condividere l’unico forno disponibile. La vita lavorativa dei pizzaioli quindi consiste
Fino a quando ci sono ordinazioni
1) Prende una ordinazione con un numero n random di pizze da 1 a 10 da preparare
2) Prepara le pizze in un tempo t=n*tp
3) Inforna un numero di pizze m che può infornare
4) Aspetta un tempo t=tc in cui le pizze vengono cotte
5) Se ha cotto tutte le pizze va al punto 1 se no va al punto 3
a) Sviluppare in linguaggio C un programma che simuli la situazione descritta commentando le scelte fatte.
Ho aggiunto un tempo di infornatura e sfonatura delle pizze...
// Includo le librerie.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
// Costanti e funzioni utili
#define N 8 // Numero posti del forno
#define TP 1 // Tempo di preparazione di una pizza
#define TC 3 // Tempo di cottura
#define GetRandom( min, max ) ((rand( ) % (int)(((max) + 1) - (min))) + (min))
// Variabile che conterrà il nome del programma (inutile)
char *progname;
/* Il mutex associato al forno e l'attributo da passare all'inizializzatore del mutex! */
pthread_mutex_t hForno;
// Ogni elemento è un posto nel forno
pthread_mutexattr_t attr;
// UTILISSIMO!!!
// Variabile condivisa per il controllo dei posti disponibili. Protetta dal mutex.
int nPostiDisponibili = N;
// Variabile di controllo del ciclo principale
int finito;
/* print error message and die */
void error
(char *f
){
extern char *progname;
if (progname
)
fprintf
(stderr,
"%s: ", progname
);
perror
(f
);
exit
(1);
}
/* suspend execution of the calling thread */
void waiting
(int min,
int max
){
sleep
(rand
()%
(max-min+
1) + min
);
}
// Routine comune ad ogni thread!
void *Pizzaiolo
(void *param
){
int id=*
(int *
)param;
// id del thread
int nPizzeOrdinate, nPizzeRimanenti, nPizzeInfornate =
0;
int evaso =
1;
// Flag di controlla l'evasione dell'ordine
int finito =
1;
// Flag che controlla il ciclo principale
while(finito
){ // Ciclo principale
if(evaso
) { // Se ho finito prendo una nuova ordinazione
nPizzeOrdinate = GetRandom
(1,
10);
nPizzeRimanenti = nPizzeOrdinate;
printf("T%d: E' arrivata un'ordinazione! Preparo %d pizze\n", id, nPizzeOrdinate
);
sleep
(nPizzeOrdinate*TP
);
printf("T%d: Ho preparato %d pizze\n", id, nPizzeOrdinate
);
evaso =
0;
// Comincio...
}
while( nPizzeRimanenti >
0 ) { // Ciclo sino a quando soddisfo l'ordine
// Controllo sui posti disponibili. Controllo che non inforno più pizze di quanto me ne rimangono.
if( nPostiDisponibili >
0 && nPizzeInfornate < nPizzeRimanenti
) {
// Controllo se il forno è occupato dall'altro pizzaiolo, se è occupato goto else, altrimenti continuo...
if(pthread_mutex_trylock
(&hForno
) ==
0 ) { // Controllo se posso accedere al forno
pthread_mutex_lock
(&hForno
);
// Blocco l'accesso al forno
printf("T%d: Forno libero. Ci sono %d posti, inforno una pizza! Me ne mancano %d..\n",id, nPostiDisponibili, nPizzeRimanenti-nPizzeInfornate -
1);
nPostiDisponibili--;
// Occupo un posto
sleep
(1);
// tempo di infornatura...serve a fare vedere che i mutex funzionano!
pthread_mutex_unlock
(&hForno
);
// Rilascio il forno...l'altro può infornare o sfornare
nPizzeInfornate++;
// Inforno una pizza
} else { // Se il forno è occupato faccio un resoconto ( non capita... )
printf("T%d: Voglio infornare ma il forno e' occupato. Aspetto! Ho gia' in forno %d pizze\n", id, nPizzeInfornate
);
sleep
(2);
// Aspetto...
continue;
// Ricomincio il ciclo sino a quando non soddisfo l'ordine
}
} else { // Se non ci sono posti disponibili oppure ho già finito di infornare le pizze ordinate...
printf("T%d: Ho %d pizze in forno...Ne rimangono %d\n",id, nPizzeInfornate, nPizzeRimanenti - nPizzeInfornate
);
nPizzeRimanenti -= nPizzeInfornate;
// A seconda di quante pizze ho infornato diminuisco in numero di pizze rimanenti
sleep
(TC
);
// Aspetto che si cuociano le pizze infornate
if(pthread_mutex_trylock
(&hForno
) ==
0 ) { // Controllo se posso accedere al forno
pthread_mutex_lock
(&hForno
);
// Blocco l'accesso al forno
nPostiDisponibili += nPizzeInfornate;
// Sforno le pizze infornate, libero i posti.
printf("T%d: Ho sfornato %d pizze delle %d ordinate! Me ne rimangono %d\n", id, nPizzeInfornate, nPizzeOrdinate, nPizzeRimanenti
);
sleep
(1);
// Tempo di sfornatura...così faccio vedere che i mutex funzionano!!!
pthread_mutex_unlock
(&hForno
);
// Sblocco l'accesso al forno
} else { // Se il forno è occupato faccio un resoconto ( non capita... )
printf("T%d: Voglio sfornare %d pizze delle %d ordinate ma il forno e' occupato. Aspetto!\n", id, nPizzeInfornate, nPizzeOrdinate
);
sleep
(1);
// Aspetto...
continue;
// Ricomincio il ciclo sino a quando non soddisfo l'ordine
}
nPizzeInfornate =
0;
// Ho tolto tutte le pizze infornate
}
} // Ho soddisfatto l'ordine!
printf("T%d: Ho cotto tutte le %d pizze ordinate!\n",id, nPizzeOrdinate
);
evaso =
1;
// L'ordine è stato evaso.
// MODIFICARE QUESTO FLAG A ZERO SE SI DESIDERA CHE I PIZZAIOLI RICEVANO UN SOLO ORDINE!!!
finito =
1;
}
return NULL;
}
// Inizia il programmino...
int main
(int argc,
char *argv
[])
{
// Inizializzo l'attributo del mutex
pthread_mutexattr_init
(&attr
);
// Mutex di tipo ERRORCHECK
pthread_mutexattr_settype
(&attr,PTHREAD_MUTEX_ERRORCHECK
);
// Struttura di un thread pizzaiolo
struct {
int id;
pthread_t thread_id;
} pizzaiolo
[2];
// Questo è il nome del programmino
progname=argv
[0];
// Via al semeeeeeeee
srand
(time
(NULL));
/* create mutex di tipo ERRORCHECK */
if (pthread_mutex_init
(&hForno, &attr
))
error
("pthread_mutex_init");
/* create and run the threads */
pizzaiolo
[0].
id =
1;
if (pthread_create
(&pizzaiolo
[0].
thread_id,
NULL, Pizzaiolo, &pizzaiolo
[0].
id))
error
("pthread_create");
pizzaiolo
[1].
id=
2;
// id del secondo thread
if (pthread_create
(&pizzaiolo
[1].
thread_id,
NULL, Pizzaiolo, &pizzaiolo
[1].
id))
error
("pthread_create");
// Per modificare finito vedere le ultime righe di codice della routine Pizzaiolo
// Se finito == 1 allora il ciclo principale è infinito, se finito == 0 allora i pizzaioli ricevono e completano un solo ordine.
/* se il ciclo principale della routine Pizzaiolo non è infinito uccido i thread quando finiscono altrimenti SIGINT per terminare! */
if( pthread_join
(pizzaiolo
[0].
thread_id,
NULL) )
error
("pthread_join");
else printf("\n\nUcciso il primo pizzaiolo! =) \n\n");
if( pthread_join
(pizzaiolo
[1].
thread_id,
NULL) )
error
("pthread_join");
else printf("\n\nUcciso il secondo pizzaiolo! =) \n\n");
return 0;
}