Ci sono N_FILOSOFI filosofi a pranzo serviti da un singolo cameriere. Il cameriere porta i pasti ai filosofi e li appoggia sulla tavola. C’è posto solo per DIM_BUFFER pasti e se non c’è posto il cameriere attende, secondo il seguente schema:
ini_scrivi();
scrivi_buffer(i); // deposita il pasto i sulla tavola
end_scrivi();
Ogni filosofo prende il primo pasto disponibile dalla tavola, raccoglie la bacchetta sinistra poi quella destra, mangia e deposita le bacchette. Lo schema del filosofo id è il seguente.
ini_leggi();
i=leggi_buffer(); // prende il pasto dalla tavola
end_leggi();
raccogli_sx(id);
raccogli_dx(id);
consuma_pasto(id,i); // consuma il pasto
deposita_sx(id);
deposita_dx(id);
Si devono realizzare le funzioni di sincronizzazione (file filosofi.c) facendo attenzione a eventuali stalli.
/* Seconda verifica di Lab Sistemi Operativi (a.a. 2011-2012)
Ricordarsi di commentare il codice e di spiegare, brevemente, la soluzione proposta
*/
// mettere qui la dichiarazione di semafori e eventuali variabili globali
void init_sem() {}
void destroy_sem() {}
void ini_leggi() {}
void end_leggi() {}
void ini_scrivi() {}
void end_scrivi() {}
void raccogli_sx(int b) {}
void raccogli_dx(int b) {}
void deposita_sx(int b) {}
void deposita_dx(int b) {}
Chiamare il file filosofi.c e testarlo con il seguente programma:
#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<semaphore.h>
#include<unistd.h>
#include<stdarg.h>
#define N_PASTI 15
#define DIM_BUFFER 3
#define N_FILOSOFI 5
#include "filosofi.c" // funzioni di sincronizzazione DA REALIZZARE PER LA VERIFICA
/********** le funzioni qui sotto sono 'ACCESSORIE' al test, non serve guardarle in dettaglio *********/
// funzioni di terminazione
void die(char * s, int i) {
printf("[ERROR] %s: %i\n",s,i);
exit(1);
}
/*void die2(char * s) {
printf("[SYNC ERROR] %s\n",s);
exit(1);
}*/
void die2(char *s, ...) {
va_list ap;
//printf("[SYNC ERROR] ",s);
va_start(ap, s);
vprintf(s,ap);
va_end(ap);
exit(1);
}
// buffer circolare
struct {
int buf[DIM_BUFFER];
int inserisci;
int preleva;
} buffer;
// scrive i nel buffer
void scrivi_buffer(int i) {
buffer.buf[buffer.inserisci]=i;
buffer.inserisci=(buffer.inserisci+1)%DIM_BUFFER;
}
// legge un intero dal buffer id
int leggi_buffer() {
int j=buffer.buf[buffer.preleva];
#ifdef CHECK_MUTEX
sleep(1);
#endif
buffer.preleva=(buffer.preleva+1)%DIM_BUFFER;
return j;
}
int bacchette_test[N_FILOSOFI]; // le bacchette, utilizzate per il test
int pasti_test[N_PASTI]; // conteggia i pasti per il test
int pasti_consumati=0; // tutti i pasti sono stati consumati
// consuma il pasto e controlla che le bacchette siano utilizzate correttamente
void consuma_pasto(int id, int i) {
int j;
int id_dx = (id+1)%N_FILOSOFI;
if (bacchette_test[id]) die2("[Filosofo %i] Bacchetta %d gia' in uso\n",id,i);
if (bacchette_test[id_dx]) die2("[Filosofo %i] Bacchetta %d gia' in uso\n",id_dx,i);
bacchette_test[id] = bacchette_test[id_dx] = 1;
printf("[Filosofo %i] Consumo il pasto %i\n",id,i);
sleep(2);
bacchette_test[id] = bacchette_test[id_dx] = 0;
if (pasti_test[i]) {
die2("[ERRORE] sto per consumare il pasto %i gia' consumato in precedenza\n",i);
}
pasti_test[i]=1; // pasto consumato
for (j=0;j<N_PASTI && pasti_test[j];j++);
if (j==N_PASTI)
pasti_consumati=1; // e' ora di uscire
}
void * cameriere(void * n) {
int i;
for (i=0;i<N_PASTI;i++) {
printf("[Cameriere] Consegno il pasto %i\n",i);
ini_scrivi();
scrivi_buffer(i); // scrive i nel buffer
end_scrivi();
}
}
void * filosofo(void * n) {
int id = * (int *) n;
int i;
while(1) {
ini_leggi();
i=leggi_buffer(); // prende il pasto dal buffer
end_leggi();
printf("[Filosofo %d] Ho ricevuto il pasto %d\n",id, i);
raccogli_sx(id);
sleep(1); // forza il deadlock
raccogli_dx(id);
consuma_pasto(id,i); // consuma il pasto
deposita_sx(id);
deposita_dx(id);
}
}
int main() {
pthread_t th1[N_FILOSOFI], th2;
int th1_id[N_FILOSOFI];
int i,ret;
// inizializza i semafori
init_sem();
for (i=0;i<N_PASTI;i++)
pasti_test[i]=0; // per il test
// crea i filosofi
for (i=0;i<N_FILOSOFI;i++) {
th1_id[i]=i;
if((ret=pthread_create(&th1[i],NULL,filosofo,&th1_id[i])))
die("errore create",ret);
printf("Creato il filosofo %i\n", th1_id[i]);
}
// fa partire il cameriere un po' dopo per verificare la sincronizzazione
sleep(2);
// crea il cameriere
if((ret=pthread_create(&th2,NULL,cameriere,NULL )))
die("errore create",ret);
printf("Creato il cameriere\n");
/* attende la terminazione
for (i=0;i<N_FILOSOFI;i++)
if((ret=pthread_join(th1[i], NULL)))
die("errore join",ret);
*/
if((ret=pthread_join(th2, NULL)))
die("errore join",ret);
for (i=0;i<5 && !pasti_consumati;i++) {
printf("[MAIN] Attendo che i pasti siano consumati\n");
sleep(10);
}
// elimina i semafori
destroy_sem();
if (i==5)
die2("I pasti non sono stati tutti consumati\n");
else {
printf("Terminato correttamente\n");
exit(0);
}
}