Due categorie di processi
Vincoli:
Scrivere un’applicazione concorrente che implementi il problema dei Produttori/Consumatori.
Il programma crei dei processi che agiscano da produttore e consumatore utilizzando un unico buffer di memoria.
I vincoli imposti da un problema di tipo Produttore-Consumatore,nel caso che il buffer sia unico e che vi siano un solo produttore ed un solo consumatore, sono i seguenti:
Per la sincronizzazione dei processi produttore e consumatore si utilizzano due semafori:
1. SPAZIO_DISP: semaforo bloccato da un produttore prima di una produzione sbloccato da un consumatore in seguito ad un consumo;
2. MSG_DISP: semaforo sbloccato da un produttore in seguito ad una produzione e bloccato da un consumatore prima del consumo.
Il messaggio prodotto consiste di un valore di tipo long, rappresentativo della data di sistema (ottenuto mediante la chiamata gettimeofday(2)) . Una siffatta soluzione permette di differenziare i valori prodotti dai vari processi produttori.
La produzione ed il consumo avvengono rispettivamente all’interno delle procedure
void Produttore(msg*,int);
void Consumatore(msg *,int);
all’interno delle quali si effettuano anche le operazioni di Wait_Sem e Signal_Sem necessarie.
/*--------HEADER FILE-------*/
#define MSG_DISP 0
#define SPAZIO_DISP 1
#define DIM 1
typedef long msg;
void Wait_Sem(int, int );
void Signal_Sem (int, int );
void Produttore(msg*,int);
void Consumatore(msg *,int);
//Procedure Consumatore
void Consumatore(msg *ptr_sh,int mutex){
msg mess;
Wait_Sem(mutex,MSG_DISP);
mess=*ptr_sh;//memcpy(&mess,ptr_sh,sizeof(mess));
printf("Messaggio letto: \n",mess);
Signal_Sem(mutex,SPAZIO_DISP);
}
//Procedure Produttore
void Produttore(msg*ptr_sh,int mutex){
struct timeval t1;
struct timezone t2;
gettimeofday(&t1,&t2);
msg val =t1.tv_usec;
Wait_Sem(mutex,SPAZIO_DISP);
printf (" <%d> Produzione in corso (%d), valore semaforo SPAZIO_DISP=%d \n",
getpid(),val,leggi_valore(mutex,SPAZIO_DISP));
*ptr_sh=val;
Signal_Sem(mutex,MSG_DISP);
}
Scrivere un’applicazione concorrente che implementi il problema dei Produttori/Consumatori utilizzando un pool di buffer gestito mediante un vettore ausiliario di STATO.
I vincoli imposti sono i seguenti:
La gestione del pool di buffer avviene mediante due vettori:
Per la sincronizzazione dei processi si possono utilizzare due mutex, MUTEXP e MUTEXC, al fine di gestire l’accesso al buffer in mutua esclusione e due semafori, PROD e CONS, per la sincronizzazione delle operazioni di produzione e consumo.
/*************DEFINZIONE DELLE COSTANTI************/
#define VUOTO 2
#define PIENO 3
#define IN_USO 4
#define MUTEXP 0
#define MUTEXC 1
#define PROD 0
#define CONS 1
typedef long msg;
La produzione di un messaggio può articolarsi nelle seguenti funzioni:
int RichiestaP (int*stato,int sem, int mutex) – Effettua una richiesta di produzione. L’algoritmo implementato consiste dei seguenti passi:
void Produzione(int indice,msg messaggio,msg *buffer) - consiste nel memorizzare il valore del messaggio nella cella buffer[indice];
void RilascioP (int indice,int*stato,int sem) – rilascia le risorse occupate durante la produzione. Essa consiste nel porre al valore PIENO lo stato relativo alla cella buffer[indice], nella quale è stato memorizzato il valore prodotto, e di sbloccare eventuali processi Consumatori mediante una signal sul semaforo CONS.
Il consumo di un messaggio può articolarsi nelle seguenti funzioni:
int RichiestaC (int*stato,int sem, int mutex) – Effettua una richiesta di consumo. L’algoritmo implementato consiste dei seguenti passi:
msg Consumo(int indice,msg * buffer) – espleta l’operazione di consumo che consiste nel leggere il valore del messaggio nella cella buffer[indice], restituendolo al chiamante;
void RilascioC(int indice,int*stato,int sem) – rilascia le risorse occupate durante l’operazione di consumo. Essa consiste nel liberare la cella buffer[indice] contenente il messaggio consumato, ponendo il valore VUOTO in stato[indice] e di sbloccare eventuali processi Produttori mediante una signal sul semaforo PROD.
Scrivere un’applicazione concorrente che implementi il problema dei Produttori/Consumatori utilizzando una coda ( pool di buffer gestito come vettore circolare).
La coda è implementata mediante i seguenti campi:
Per la sincronizzazione dei processi sono stati utilizzati due semafori, SPAZIO_DISP e NUM_MESS, che indicano rispettivamente la presenza di spazio disponibile in coda per la produzione di un messaggio e il numero di messaggi presenti in coda.
void Produttore() {
Wait(SPAZIO_DISP);
//Memorizzazione del valore prodotto
buffer[(testa)]=valore_prodotto;
testa=++(testa) % DIM; //gestione circolare degli indici
Signal(NUM_MESS); //nelem=nelem+1
}
void Consumatore(){
Wait(NUM_MESS);
//Consumo
mess=buffer[coda];
(coda)=++(coda) %DIM; //gestione circolare degli indici
printf("Messaggio letto: <%d> \n",mess);
Signal(SPAZIO_DISP); // nelem=nelem-1
}
Scrivere un’applicazione concorrente per il calcolo della somma degli elementi contenuti in una matrice.
Vincoli
La matrice e il buffer sums devono essere immagazzinati in memoria condivisa.
I processi P_i accedono al buffer sums per la somma della colonna i-sima in mutua esclusione senza alcun vincolo sulla posizione (e.s. Il processo P2 termina per primo e scrive nella casella sums[0]; il processo P1 finisce per secondo e scrive nella casella sums[1], ecc.)
Il processo P (per la somma totale) resta in attesa della terminazione di tutti i processi P_i. Implementare tale attesa con una wait_for_zero.
Il processo padre (diverso da P) attende la terminazione di tutti i processi e restituisce a video il totale calcolato da P (anch’esso memorizzato in shm).
1. Introduzione ai Sistemi Operativi
5. Scheduling nei sistemi mono-processore
6. Threads, SMP
8. Scheduling Multiprocessore e Real-Time
9. Gestione dei processi nei sistemi operativi Unix/Linux e Window...
10. Introduzione alla Programmazione Concorrente
11. Sincronizzazione nel modello ad ambiente globale
12. Problemi di cooperazione nel modello ad ambiente globale
14. Sincronizzazione nel modello ad ambiente locale
15. Deadlock
16. Programmazione Multithread
18. Memoria Virtuale
20. Il File System
21. Primitive di sincronizzazione nel kernel Linux
22. Esercitazione: System call per la gestione dei processi
23. Esercitazione: Inteprocess Communication e Shared Memory
24. Esercitazione: System Call per la gestione dei semafori in Linu...
25. Esercitazione: Problema dei Produttori e dei Consumatori
26. Posix Threads