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); } }