[semafori] Imbuto 2.0

NOTA: per chi usa Mac questo esercizio può essere solo risolto usando docker o una VM linux in quanto il programma principale usa i semafori senza nome (vedere qui per maggiori dettagli). Lo stesso vale per la verifica con bonus.

Si devono sincronizzare un certo numero di thread pallina in modo che entrino in un imbuto solo a gruppi di una dimensione prefissata N e, dopo un certo tempo, escono dall’imbuto. Solo nel momento in cui sono usciti tutti, il gruppo successivo di N thread pallina può accedere.

ATTENZIONE: non è il thread principale a sbloccare i gruppi di thread pallina, ma sono le palline stesse che si sincronizzano autonomamente.

Il thread principale si limita a inizializzare i semafori, creare i thread pallina attendere la loro terminazione e eliminare i semafori, secondo il seguente schema. La dimensione dei gruppi N viene passata a inizializza_sem in modo da poter essere utilizzata, successivamente, per la sincronizzazione.

inizializza_sem(N); // inizializza i semafori e salva N

// Crea i thread pallina e attende la loro terminazione

distruggi_sem(); // distruggi i semafori

Lo schema del thread pallina è il seguente:

entra_imbuto(); // attende di entrare nell'imbuto

// entra nell'imbuto e percorri tutta la strada verso il fondo

esci_imbuto(); // esce dall'imbuto 

L’obiettivo della verifica è di implementare le 2 funzioni di sincronizzazione entra_imbuto e esci_imbuto tramite semafori (più le 2 funzioni inizializza_sem e distruggi_sem per inizializzare e eliminare i semafori) in modo da realizzare il comportamento richiesto.

IMPORTANTE: la funzione esci_imbuto deve necessariamente contare il numero di palline che sono uscite dall’imbuto per poi sbloccare il gruppo successivo: questa sincronizzazione non è realizzabile utilizzando solamente sem_wait e sem_post sui semafori. Utilizzare, a tale scopo, una variabile globale proteggendo opportunamente la sezione critica. Non ci sono problemi a fare delle sem_post su altri semafori dentro una sezione critica perché le sem_post non sono mai bloccanti.

Le funzioni da implementare sono nel file soluzione.c che va compilato assieme a imbuto2.c (scarica lo zip). Compilare con gcc soluzione.c imbuto2.c -o imbuto2 -pthread.

Una volta che funziona, compilare con l’opzione -DSTRESSTEST che testa il programma con un numero elevato di thread e senza sleep (in modo da aumentare la probabilità di race condition):

gcc soluzione.c imbuto2.c -o imbuto2 -pthread -DSTRESSTEST

Per ripetere il test in automatico potete usare questo semplice script bash:

while true; do if ! ./imbuto2 ; then break; fi; done