Soluzione
Ecco una possibile soluzione commentata della verifica:
[sourcecode lang=”C”]
/*
* COMMENTO GENERALE:
*
* Utilizziamo due semafori. Immaginiamo che ogni semaforo
* corrisponda a una risorsa e il suo valore alla disponibilità
* di tale risorsa:
*
* – sem_imbuto: corrisponde alla risorsa imbuto, che le palline
* richiedono per poter accedervi. Inizialmente vale 0
* (rosso) in quanto le palline devono attendere che il
* thread principale conceda loro l’accesso;
*
* – sem_pallina: corrisponde alla risorsa pallina che ha percorso
* l’imbuto fino all’uscita. Inizialmente vale 0 perché
* nessuna pallina è ancora transitata. Il thread principale
* attende la fuoriuscita delle palline su questo semaforo.
*
* Sincronizzazione:
*
* Thread pallina: per accedere all’imbuto la pallina effettua
* una wait sul semaforo sem_imbuto (funzione entra_imbuto) che
* ne regola, appunto, l’accesso. Quando esce dall’imbuto
* segnala la sua presenza facendo una post sul semaforo
* sem_pallina (funzione esci_imbuto), che conta quante palline
* sono transitate attraverso l’imbuto.
*
* Thread principale: il thread principale sblocca n palline
* effettuando n post sul semaforo sem_imbuto (fun. sblocca(n)).
* Intuitivamente è come se concedesse n risorse imbuto alle
* palline che le stanno richiedendo. Poiché ogni pallina fa
* una singola wait (chiede una risorsa imbuto), ogni post
* sbloccherà esattamente un thread pallina in attesa. Quindi
* le n post sbloccheranno n palline, come richiesto.
* Il thread principale, in seguito, attende la fuoriuscita
* di n palline effettuando n wait sul semaforo sem_pallina
* (funzione attendi(n)). Poiché il semaforo è inizializzato
* a 0 il thread si sbloccherà dalle n wait solo quando n
* thread pallina effettueranno le relative post, ovvero
* quando usciranno dall’imbuto (funzione esci_imbuto), come
* richiesto.
*
* Riconduzione a un problema standard: la soluzione è, di
* fatto, una variante del produttore-consumatore in cui
* i thread pallina consumano una risorsa imbuto, prodotta
* a "lotti" di n dal thread principale, e il thread principale
* consuma la risorsa pallina, prodotte dagli n thread pallina
* che fuoriescono dall’imbuto. Come per le celle piene e
* vuote del buffer nel produttore-consumatore, si utilizzano
* due semafori contatori. La sincronizzazione, però, è
* alternativamente:
*
* – uno a molti: il thread principale che sblocca n thread
* pallina (effettuando n post, che concedono n risorse)
*
* – molti a uno: gli n thread pallina che sbloccano il thread
* principale (in attesa su n wait, che allocano n risorse)
*/
// dichiarazione semafori
sem_t sem_imbuto, // regola l’accesso all’imbuto
sem_pallina; // regola la fuoriuscita dall’imbuto
// inizializza i semafori
void inizializza_sem() {
// i semafori sono inizializzato a 0 in quanto, inizialmente,
// non ci sono risorse imbuto o pallina disponibili:
// tutte le wait saranno bloccanti.
sem_init(&sem_imbuto,0,0); // nessun accesso all’imbuto
sem_init(&sem_pallina,0,0); // nessuna pallina è ancora fuoriuscita
}
// distruggi i semafori
void distruggi_sem() {
sem_destroy(&sem_imbuto); // elimina il semaforo imbuto
sem_destroy(&sem_pallina); // elimina il semaforo pallina
}
// attende di entrare nell’imbuto
void entra_imbuto() {
// per accedere all’imbuto la pallina effettua una wait sul
// semaforo imbuto che ne regola, appunto, l’accesso:
// di fatto, consuma una risorsa imbuto.
sem_wait(&sem_imbuto);
}
// esce dall’imbuto
void esci_imbuto() {
// Quando la pallina esce dall’imbuto segnala la sua presenza
// facendo una post sul semaforo pallina, che conta quante
// palline sono transitate attraverso l’imbuto: produce una
// risorsa pallina.
sem_post(&sem_pallina);
}
// fa entrare n thread "pallina" nell’imbuto
void sblocca(int n) {
// Il thread principale sblocca n palline effettuando n post
// sul semaforo imbuto: produce n risorse imbuto.
int i;
for (i=0;i<n;i++) sem_post(&sem_imbuto);
}
// attende che n thread "pallina" escano dall’imbuto
void attendi(int n) {
// Il thread principale attende la fuoriuscita di n palline
// effettuando n wait sul semaforo pallina: consuma n risorse
// pallina
int i;
for (i=0;i<n;i++) sem_wait(&sem_pallina);
}
[/sourcecode]