Appunti per Scuola e Università
humanisticheUmanistiche
Appunti e tesine di tutte le materie per gli studenti delle scuole medie riguardanti le materie umanistiche: dall'italiano alla storia riguardanti le materie umanistiche: dall'italiano alla storia 
sceintificheScientifiche
Appunti, analisi, compresione per le scuole medie suddivisi per materie scientifiche, per ognuna troverai appunti, dispense, esercitazioni, tesi e riassunti in download.
tecnicheTecniche
Gli appunti, le tesine e riassunti di tecnica amministrativa, ingegneria tecnico, costruzione. Tutti gli appunti di AppuntiMania.com gratis!
Appunti
informatica
CComputerDatabaseInternetJava
Linux unixReti


AppuntiMania.com » Informatica » Appunti di computer » Problemi di mutua esclusione nel modello a memoria comune

Problemi di mutua esclusione nel modello a memoria comune




Visite: 950Gradito:apreciate 5-stela [ Grande appunti ]
Leggi anche appunti:

Supermercati e informatica


  SUPERMERCATI E INFORMATICA     Indice: Ø    Introduzione Ø    Cenni

Il più semplice - computer


Il più semplice La CPU si occupa di eseguire tutte le operazioni e i calcoli necessari

Impianto per la gestione di un magazzino intermedio


UNIVERSITA' DEGLI STUDI DI NAPOLI FEDERICO II Facoltà di Ingegneria Corso
immagine di categoria



Scarica gratis Problemi di mutua esclusione nel modello a memoria comune

Problemi di mutua esclusione nel modello a memoria comune


I) Scrivere una applicazione concorrente che generi due processi figlio che competano per l'uso di un buffer di memoria (un processo figlio si comporti da lettore e l'altro da scrittore).




Descrizione: Il programma seguente implementa il problema dei Lettori/Scrittori nel caso particolare in cui ci sia un solo processo lettore ed un solo processo scrittore, ai quali si estendono i seguenti vincoli:

la lettura del buffer di memoria comune (allocato dal processo padre) da parte del processo lettore non può avvenire se non dopo la scrittura da parte del processo scrittore, e chiaramente il processo lettore non ha facoltà di modificare il contenuto del buffer.

il processo scrittore opera ogni volta una "sovrascrittura" del contenuto del buffer.

A garanzia della consistenza del contenuto del buffer condiviso, processo lettore e processo scrittore devono accedervi in mutua esclusione.


Semafori.H


#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>


void Init_Sem(int, int); //Inizializza Semaforo


void Wait_Sem(int, int); //Wait su Semaforo


void Signal_Sem(int, int);     //Signal su Semaforo


int Awaiting_Sem(int, int);   //Restituisce il numero di processi in attesa su Semaforo


Semafori.C


#include 'semafori.h'


struct sembuf Sem_Buf; //sembuf è un tipo predefinito contenente perlomeno i seguenti campi

//short sem_num; Numero del semaforo

//short sem_op; Valore da sommare algebricamente al semaforo

//short sem_flg; Flag dell'operazione


union semun Sem_Union;                             //semun è una unione predefinita contenente i seguenti elementi

//int val;

//struct semid_ds* buf;

//unshort_t* array;


//----- Nelle funzioni seguenti ID identifica il gruppo di semafori, N il singolo semaforo nel gruppo -----


void Init_Sem(int ID, int N, int Val)


void Wait_Sem(int ID, int N)


void Signal_Sem(int ID, int N)


int Awaiting_Sem(int ID, int N)


Programma I.C


#include <stdio.h>         

#include <sys/shm.h>     

#include <sys/wait.h>         

#include 'semafori.h'


#define DIM 1   //Dimensione dell'area di memoria condivisa

#define NUM_OPS 4 //Numero di letture/scritture


#define MUTEX 0                  //Definizione di MACRO per l'accesso al semaforo

#define INITIALIZE(S,V) Init_Sem(ID_Sem,S,V)

#define WAIT(S) Wait_Sem(ID_Sem,S)

#define SIGNAL(S) Signal_Sem(ID_Sem,S)


void main()


Ptr_Buf=shmat(ID_Buf, 0, 0); //Il segmento allocato viene annesso al segmento dati

//del processo al primo indirizzo disponibile così come

//specificato dal sistema

if (Ptr_Buf==(char*)-1)


//----- CREAZIONE SEMAFORO -----


key_t Key_Sem=IPC_PRIVATE; //Chiave del semaforo/i

int ID_Sem; //Identificatore del semaforo/i


ID_Sem=semget(Key_Sem, 1, IPC_CREAT|0664); //Viene allocato un gruppo di semafori di cardinalità 1,

//viene associato al gruppo un ID e viene creata una

//struttura dati ausiliaria che consenta di gestirlo

//RW per User, RW per Gruppo, R only per Others

if (ID_Sem==-1)


INITIALIZE(MUTEX,1); //Setta MUTEX a 1


//----- GENERAZIONE FIGLIO SCRITTORE -----


pid=fork(); //Generazione del figlio Scrittore

if (pid==-1) else if (!pid)


exit(0); //Il figlio Scrittore termina correttamente


}


//----- GENERAZIONE FIGLIO LETTORE -----


pid=fork();

if (pid==-1) else if (!pid)


exit(0); //Il figlio Lettore termina correttamente

}


//----- SINCRONIZZAZIONE DEL PADRE CON I FIGLI -----


for(i=0; i<2; i++)


//----- RILASCIO MEMORIA CONDIVISA E SEMAFORO -----


shmctl(ID_Buf, IPC_RMID, 0);

semctl(ID_Sem, 0, IPC_RMID);































































































Problemi di cooperazione nel modello a memoria comune


II) Scrivere una applicazione concorrente che implementi il problema Produttore/Consumatore. In particolare, il programma crei due processi che agiscono, rispettivamente da produttore e consumatore, comunicando attraverso un unico buffer di memoria.


Descrizione: Il programma seguente implementa il problema dei Produttori/Consumatori nel caso particolare in cui ci sia un solo processo produttore ed un solo processo consumatore, ai quali si estendono i seguenti vincoli:

il consumo del buffer di memoria comune (allocato dal processo padre) da parte del processo consumatore non può avvenire se non dopo che il processo produttore vi abbia depositato un contenuto, e all'atto del consumo tale contenuto viene cancellato.

il processo produttore non può depositare nel buffer di memoria comune un nuovo contenuto se il precedente non è stato ancora consumato.

A garanzia della consistenza del contenuto del buffer condiviso, processo consumatore e processo produttore devono accedervi in mutua esclusione.


Semafori.H (L'implementazione è quella indicata per il programma I)


#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>


void Init_Sem(int, int); //Inizializza Semaforo


void Wait_Sem(int, int); //Wait su Semaforo


void Signal_Sem(int, int);     //Signal su Semaforo


int Awaiting_Sem(int, int);   //Restituisce il numero di processi in attesa su Semaforo


Programma II.C


#include <stdio.h>         

#include <sys/shm.h>     

#include <sys/wait.h>         

#include 'semafori.h'


#define DIM 1   //Dimensione dell'area di memoria condivisa

#define NUM_OPS 4 //Numero di produzioni/consumi


#define SPAZIO_DISPONIBILE 0 //Definizione di MACRO per l'accesso ai semafori

#define MESSAGGIO_DISPONIBILE 1

#define INITIALIZE(S,V) Init_Sem(ID_Sem,S,V)

#define WAIT(S) Wait_Sem(ID_Sem,S)

#define SIGNAL(S) Signal_Sem(ID_Sem,S)


void main()


Ptr_Buf=shmat(ID_Buf, 0, 0); //Il segmento allocato viene annesso al segmento dati

//del processo al primo indirizzo disponibile così come

//specificato dal sistema

if (Ptr_Buf==(char*)-1)


//----- CREAZIONE SEMAFORI -----


key_t Key_Sem=IPC_PRIVATE; //Chiave del semaforo/i

int ID_Sem; //Identificatore del semaforo/i


ID_Sem=semget(Key_Sem, 2, IPC_CREAT|0664); //Viene allocato un gruppo di semafori di cardinalità 2,

//viene associato al gruppo un ID e viene creata una

//struttura dati ausiliaria che consenta di gestirlo

//RW per User, RW per Gruppo, R only per Others

if (ID_Sem==-1)


INITIALIZE(SPAZIO_DISPONIBILE,1); //Setta SPAZIO_DISPONIBILE a 1

INITIALIZE(MESSAGGIO_DISPONIBILE,0); //Setta MESSAGGIO_DISPONIBILE a 0


//----- GENERAZIONE FIGLIO PRODUTTORE -----


pid=fork(); //Generazione del figlio Produttore

if (pid==-1) else if (!pid)


exit(0); //Il figlio Produttore termina correttamente


}


//----- GENERAZIONE FIGLIO CONSUMATORE -----


pid=fork();

if (pid==-1) else if (!pid)


exit(0); //Il figlio Consumatore termina correttamente

}


//----- SINCRONIZZAZIONE DEL PADRE CON I FIGLI -----


for(i=0; i<2; i++)


//----- RILASCIO MEMORIA CONDIVISA E SEMAFORO -----


shmctl(ID_Buf, IPC_RMID, 0);

semctl(ID_Sem, 0, IPC_RMID);

























Problemi di cooperazione  nel modello a memoria comune


III) Scrivere un'applicazione concorrente che implementi il problema Produttore/Consumatore nella variante che prevede più produttori e consumatori che comunicano attraverso un pool di buffer di memoria gestito come vettore circolare.


Descrizione: Il programma seguente implementa il problema dei Produttori/Consumatori (più di uno) nel caso in cui essi si contendano un pool di buffer organizzato come coda circolare (inserimento in coda, prelievo in testa), posto che ad essi si applichino i seguenti vincoli:

il consumo di un singolo buffer di memoria comune (l'insieme del pool è allocato dal processo padre) da parte di un processo consumatore non può avvenire se non dopo che almeno un processo produttore vi abbia depositato un contenuto, e all'atto del consumo tale contenuto viene cancellato.

un processo produttore non può depositare in un buffer di memoria comune un nuovo contenuto se non è disponibile alcun buffer libero.

A garanzia della consistenza del contenuto del buffer condiviso, processi consumatori e processi produttori, globalmente, devono accedere al singolo buffer in mutua esclusione, tuttavia l'accesso al pool di buffer nella sua totalità avviene comunque in concorrenza


Semafori.H (L'implementazione è quella indicata per il programma I)


#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>


void Init_Sem(int, int); //Inizializza Semaforo


void Wait_Sem(int, int); //Wait su Semaforo


void Signal_Sem(int, int);     //Signal su Semaforo


int Awaiting_Sem(int, int);   //Restituisce il numero di processi in attesa su Semaforo


Prod_Cons_Queue.H


#include <stdio.h>

#include "semafori.h"


#define DIM_QUEUE 4          //Cardinalità della Coda circolare

#define VUOTO 0       //Stati del singolo buffer della Coda circolare

#define IN_USO 1

#define PIENO 2


typedef struct Queue;


void Init_Queue(Queue*);      //Inizializza la Coda circolare


void Init_Semafori_Queue(int);                               //Inizializza i semafori


int Richiesta_Produzione_Queue(Queue*, int);                  //Richiesta di un buffer libero per la produzione


void Produzione_Queue(int, char, Queue*); //Produzione di un carattere nella Coda circolare


void Rilascio_Produzione_Queue(int, Queue*, int);           //Rilascio di un buffer pieno


int Richiesta_Consumo_Queue(Queue*, int);                     //Richiesta di un buffer pieno per il consumo


char Consumo_Queue(int, Queue*);                        //Consumo di un carattere dalla Coda circolare


void Rilascio_Consumo_Queue(int, Queue*, int);  //Rilascio di un buffer vuoto


Prod_Cons_Queue.C


#include "prod_cons_queue.h"


#define SPAZIO_DISPONIBILE 0 //Definizione di MACRO per l'accesso ai semafori

#define MESSAGGIO_DISPONIBILE 1

#define MUTEX_PROD 2

#define MUTEX_CONS 3

#define INITIALIZE(S,V) Init_Sem(ID_Sem,S,V)

#define WAIT(S) Wait_Sem(ID_Sem,S)

#define SIGNAL(S) Signal_Sem(ID_Sem,S)


void Init_Queue(Queue* Q)


void Init_Semafori_Queue(int ID_Sem)


int Richiesta_Produzione_Queue(Queue* Q, int ID_Sem) while (Q->stato[Q->coda]!=VUOTO);

Q->stato[i]=IN_USO;


SIGNAL(MUTEX_PROD);


printf('Buffer %d in uson', i);

return i;



void Produzione_Queue(int i, char value, Queue* Q)


void Rilascio_Produzione_Queue(int i, Queue* Q, int ID_Sem)


int Richiesta_Consumo_Queue(Queue* Q, int ID_Sem)

if (i==Q->testa) Q->testa=(Q->testa+1) % DIM_QUEUE;

Q->stato[i]=IN_USO;


SIGNAL(MUTEX_CONS);


printf('Buffer %d in uson', i);

return i;



char Consumo_Queue(int i, Queue* Q)


void Rilascio_Consumo_Queue(int i, Queue* Q, int ID_Sem)


Programma III.C


#include <stdio.h>         

#include <sys/shm.h>

#include <sys/wait.h>         

#include 'prod_cons_queue.h'


#define DIM sizeof(Queue)              //Dimensione dell'area di memoria condivisa

#define NUM_PROD 3    //Numero di processi produttori

#define NUM_PRODUZ 5     //Numero di produzioni per ogni processo produttore

#define NUM_CONS 5     //Numero di processi consumatori

#define NUM_CONSUM 3     //Numero di consumi per ogni processo consumatore


void main()


Ptr_Buf=(Queue*)shmat(ID_Buf, 0, 0); //Il segmento allocato viene annesso al segmento dati

//del processo al primo indirizzo disponibile così come

//specificato dal sistema

if (Ptr_Buf==(Queue*)-1)


Init_Queue(Ptr_Buf); //Inizializzazione della Queue


//----- CREAZIONE SEMAFORI -----


key_t Key_Sem=IPC_PRIVATE; //Chiave del semaforo/i

int ID_Sem; //Identificatore del semaforo/i


ID_Sem=semget(Key_Sem, 4, IPC_CREAT|0664); //Viene allocato un gruppo di semafori di cardinalità 4,

//viene associato al gruppo un ID e viene creata una

//struttura dati ausiliaria che consenta di gestirlo

//RW per User, RW per Gruppo, R only per Others

if (ID_Sem==-1)


Init_Semafori_Queue(ID_Sem); //Inizializzazione dei semafori


//----- GENERAZIONE FIGLI PRODUTTORI -----


for(i=0; i<NUM_PROD; i++) {


pid=fork(); //Generazione del figlio Produttore i-esimo

if (pid==-1) else if (!pid)


exit(0); //Il figlio Produttore termina correttamente

}


} //End For NUM_PROD


//----- GENERAZIONE FIGLI CONSUMATORI -----


for(i=0; i<NUM_CONS; i++) {


pid=fork(); //Generazione del figlio Consumatore i-esimo

if (pid==-1) else if (!pid)


exit(0); //Il figlio Consumatore termina correttamente

}


} //End For NUM_CONS


//----- SINCRONIZZAZIONE DEL PADRE CON I FIGLI -----


for(i=0; i<NUM_PROD+NUM_CONS; i++)


//----- RILASCIO MEMORIA CONDIVISA E SEMAFORO -----


shmctl(ID_Buf, IPC_RMID, 0);

semctl(ID_Sem, 0, IPC_RMID);














Problemi di cooperazione nel modello a memoria comune


IV) Scrivere una applicazione concorrente che implementi il problema Produttore/Consumatore nella variante che prevede più produttori e consumatori e l'impiego di un pool di buffer di memoria.


Descrizione: Il programma seguente implementa il problema dei Produttori/Consumatori (più di uno) nel caso in cui essi si contendano un pool di buffer organizzato come semplice vettore, posto che ad essi si applichino i seguenti vincoli:

il consumo di un singolo buffer di memoria comune (l'insieme del pool è allocato dal processo padre) da parte di un processo consumatore non può avvenire se non dopo che almeno un processo produttore vi abbia depositato un contenuto, e all'atto del consumo tale contenuto viene cancellato.

un processo produttore non può depositare in un buffer di memoria comune un nuovo contenuto se non è disponibile alcun buffer libero.

A garanzia della consistenza del contenuto del buffer condiviso, processi consumatori e processi produttori, globalmente, devono accedere al singolo buffer in mutua esclusione, tuttavia l'accesso al pool di buffer nella sua totalità avviene comunque in concorrenza.


Semafori.H (L'implementazione è quella indicata per il programma I)


#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>


void Init_Sem(int, int); //Inizializza Semaforo


void Wait_Sem(int, int); //Wait su Semaforo


void Signal_Sem(int, int);     //Signal su Semaforo


int Awaiting_Sem(int, int);   //Restituisce il numero di processi in attesa su Semaforo


Prod_Cons_Vector.H


#include <stdio.h>

#include "semafori.h"


#define DIM_VECTOR 4       //Cardinalità del vettore

#define VUOTO 0       //Stati del singolo buffer del vettore

#define IN_USO 1

#define PIENO 2


typedef struct Vector;


void Init_Vector(Vector*); //Inizializza il vettore


void Init_Semafori_Vector(int);                              //Inizializza i semafori


int Richiesta_Produzione_Vector(Vector*, int);     //Richiesta di un buffer libero per la produzione


void Produzione_Vector(int, char, Vector*); //Produzione di un carattere nel vettore


void Rilascio_Produzione_Vector(int, Vector*, int);          //Rilascio di un buffer pieno


int Richiesta_Consumo_Vector(Vector*, int);                    //Richiesta di un buffer pieno per il consumo


char Consumo_Vector(int, Vector*); //Consumo di un carattere dal vettore


void Rilascio_Consumo_Vector(int, Vector*, int); //Rilascio di un buffer vuoto


Prod_Cons_Vector.C


#include "prod_cons_vector.h"


#define SPAZIO_DISPONIBILE 0 //Definizione di MACRO per l'accesso ai semafori

#define MESSAGGIO_DISPONIBILE 1

#define MUTEX_PROD 2

#define MUTEX_CONS 3

#define INITIALIZE(S,V) Init_Sem(ID_Sem,S,V)

#define WAIT(S) Wait_Sem(ID_Sem,S)

#define SIGNAL(S) Signal_Sem(ID_Sem,S)


void Init_Vector(Vector* V)


void Init_Semafori_Vector(int ID_Sem)


int Richiesta_Produzione_Vector(Vector* V, int ID_Sem)

V->stato[i]=IN_USO;


SIGNAL(MUTEX_PROD);


printf('Buffer %d in uson', i);

return i;



void Produzione_Vector(int i, char value, Vector* V)


void Rilascio_Produzione_Vector(int i, Vector* V, int ID_Sem)


int Richiesta_Consumo_Vector(Vector* V, int ID_Sem)

V->stato[i]=IN_USO;


SIGNAL(MUTEX_CONS);


printf('Buffer %d in uson', i);

return i;



char Consumo_Vector(int i, Vector* V)


void Rilascio_Consumo_Vector(int i, Vector* V, int ID_Sem)


Programma IV.C


#include <stdio.h>         

#include <sys/shm.h>

#include <sys/wait.h>         

#include 'prod_cons_vector.h'


#define DIM sizeof(Vector)              //Dimensione dell'area di memoria condivisa

#define NUM_PROD 3    //Numero di processi produttori

#define NUM_PRODUZ 5     //Numero di produzioni per ogni processo produttore

#define NUM_CONS 5     //Numero di processi consumatori

#define NUM_CONSUM 3     //Numero di consumi per ogni processo consumatore




void main()


Ptr_Buf=(Vector*)shmat(ID_Buf, 0, 0); //Il segmento allocato viene annesso al segmento dati

//del processo al primo indirizzo disponibile così come

//specificato dal sistema

if (Ptr_Buf==(Vector*)-1)


Init_Vector(Ptr_Buf); //Inizializzazione del Vettore


//----- CREAZIONE SEMAFORI -----


key_t Key_Sem=IPC_PRIVATE; //Chiave del semaforo/i

int ID_Sem; //Identificatore del semaforo/i


ID_Sem=semget(Key_Sem, 4, IPC_CREAT|0664); //Viene allocato un gruppo di semafori di cardinalità 4,

//viene associato al gruppo un ID e viene creata una

//struttura dati ausiliaria che consenta di gestirlo

//RW per User, RW per Gruppo, R only per Others

if (ID_Sem==-1)


Init_Semafori_Vector(ID_Sem); //Inizializzazione dei semafori


//----- GENERAZIONE FIGLI PRODUTTORI -----


for(i=0; i<NUM_PROD; i++) {


pid=fork(); //Generazione del figlio Produttore i-esimo

if (pid==-1) else if (!pid)


exit(0); //Il figlio Produttore termina correttamente

}


} //End For NUM_PROD


//----- GENERAZIONE FIGLI CONSUMATORI -----


for(i=0; i<NUM_CONS; i++) {


pid=fork(); //Generazione del figlio Consumatore i-esimo

if (pid==-1) else if (!pid)


exit(0); //Il figlio Consumatore termina correttamente

}


} //End For NUM_CONS


//----- SINCRONIZZAZIONE DEL PADRE CON I FIGLI -----


for(i=0; i<NUM_PROD+NUM_CONS; i++)


//----- RILASCIO MEMORIA CONDIVISA E SEMAFORO -----


shmctl(ID_Buf, IPC_RMID, 0);

semctl(ID_Sem, 0, IPC_RMID);






















Problemi di mutua esclusione nel modello a memoria comune


V) Scrivere una applicazione concorrente che implementi il problema dei  Lettori/Scrittori nella variante che prevede che essi accedano ad un pool di buffer di memoria condivisa, con attesa indefinita dei processi scrittori.


Descrizione: Il programma seguente implementa il problema dei Lettori/Scrittori (più di uno) nel caso in cui si assuma che i processi lettori abbiano la massima priorità e che i processi scrittori possano invece subire starvation. I vincoli possono essere così riassunti:

Il processo scrittore attivo opera ogni volta una "sovrascrittura" del contenuto del buffer.

Finchè è attivo un processo scrittore i processi lettori e gli altri processi scrittori devono attendere (a garanzia della consistenza del contenuto del buffer).

Finchè sono attivi uno o più processi lettori i processi scrittori devono attendere.

Finchè è attivo almeno un processo lettore tutti i processi lettori che sopraggiungono hanno diritto di prelazione rispetto ad eventuali processi scrittori già in attesa.


Semafori.H (L'implementazione è quella indicata per il programma I)


#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>


void Init_Sem(int, int); //Inizializza Semaforo


void Wait_Sem(int, int); //Wait su Semaforo


void Signal_Sem(int, int);     //Signal su Semaforo


int Awaiting_Sem(int, int);   //Restituisce il numero di processi in attesa su Semaforo


Lett_Scrit_StarvScr.H


#include <stdio.h>

#include"semafori.h"


typedef struct Buffer;


void Init_Buffer(Buffer*);      //Inizializza il vettore


void Init_Semafori(int);         //Inizializza i semafori


void Inizio_Lettura(Buffer*, int);                            //Acquisizione del buffer in lettura


char Lettura(Buffer*);                        //Lettura del buffer


void Fine_Lettura(Buffer*, int);                              //Rilascio del buffer dopo una lettura


void Inizio_Scrittura(int);      //Acquisizione del buffer per la scrittura


void Scrittura(char, Buffer*); //Scrittura del buffer


void Fine_Scrittura(int);         //Rilascio del buffer dopo una scrittura


Lett_Scrit_StarvScr.C


#include "Lett_Scrit_StarvScr.h"


#define MUTEX 0                  //Definizione di MACRO per l'accesso ai semafori

#define SYNCH 1

#define INITIALIZE(S,V) Init_Sem(ID_Sem,S,V)

#define WAIT(S) Wait_Sem(ID_Sem,S)

#define SIGNAL(S) Signal_Sem(ID_Sem,S)


void Init_Buffer(Buffer* B)


void Init_Semafori(int ID_Sem)


void Inizio_Lettura(Buffer* B, int ID_Sem)


SIGNAL(MUTEX);



char Lettura(Buffer* B)



void Fine_Lettura(Buffer* B, int ID_Sem)


SIGNAL(MUTEX);



void Inizio_Scrittura(int ID_Sem)


void Scrittura(char value, Buffer* B)


void Fine_Scrittura(int ID_Sem)


Programma V.C


#include <stdio.h>         

#include <sys/shm.h>     

#include <sys/wait.h>         

#include 'lett_scrit_starvscr.h'


#define DIM sizeof(Buffer)              //Dimensione dell'area di memoria condivisa

#define NUM_LETT 5   //Numero di processi lettori

#define NUM_SCRIT 2                                //Numero di processi scrittori


void main()


Ptr_Buf=(Buffer*)shmat(ID_Buf, 0, 0); //Il segmento allocato viene annesso al segmento dati

//del processo al primo indirizzo disponibile così come

//specificato dal sistema

if (Ptr_Buf==(Buffer*)-1)


Init_Buffer(Ptr_Buf); //Inizializzazione del Buffer


//----- CREAZIONE SEMAFORI -----


key_t Key_Sem=IPC_PRIVATE; //Chiave del semaforo/i

int ID_Sem; //Identificatore del semaforo/i


ID_Sem=semget(Key_Sem, 2, IPC_CREAT|0664); //Viene allocato un gruppo di semafori di cardinalità 2,

//viene associato al gruppo un ID e viene creata una

//struttura dati ausiliaria che consenta di gestirlo

//RW per User, RW per Gruppo, R only per Others

if (ID_Sem==-1)


Init_Semafori(ID_Sem); //Inizializzazione dei semafori


//----- GENERAZIONE FIGLI SCRITTORI -----


for(i=0; i<NUM_SCRIT; i++) {


pid=fork(); //Generazione del figlio Scrittore i-esimo

if (pid==-1) else if (!pid)


Inizio_Scrittura(ID_Sem);

Scrittura(value, Ptr_Buf);

Fine_Scrittura(ID_Sem);


exit(0); //Il figlio Scrittore termina correttamente

}


} //End For NUM_SCRIT


//----- GENERAZIONE FIGLI LETTORI -----


for(i=0; i<NUM_LETT; i++) {


pid=fork(); //Generazione del figlio Lettore i-esimo

if (pid==-1) else if (!pid)


} //End For NUM_LETT


//----- SINCRONIZZAZIONE DEL PADRE CON I FIGLI -----


for(i=0; i<NUM_SCRIT+NUM_LETT; i++)


//----- RILASCIO MEMORIA CONDIVISA E SEMAFORO -----


shmctl(ID_Buf, IPC_RMID, 0);

semctl(ID_Sem, 0, IPC_RMID);








































Problemi di mutua esclusione nel modello a memoria comune


VI) Scrivere una applicazione concorrente che implementi il problema dei  Lettori/Scrittori nella variante che prevede che essi accedano ad un pool di buffer di memoria condivisa, con attesa indefinita sia dei processi scrittori che dei processi lettori.


Descrizione: Il programma seguente implementa il problema dei Lettori/Scrittori (più di uno) nel caso in cui si assuma che sia i processi lettori che i processi scrittori abbiano (quando attivi) la massima priorità sui processi dell'altra categoria, sicché ambedue le classi di processi possono subire starvation. I vincoli possono essere così riassunti:

Il processo scrittore attivo opera ogni volta una "sovrascrittura" del contenuto del buffer.

Finchè è attivo un processo scrittore i processi lettori e gli altri processi scrittori devono attendere (a garanzia della consistenza del contenuto del buffer).

Finchè sono attivi uno o più processi lettori i processi scrittori devono attendere, e finquando è attivo almeno un processo lettore tutti i processi lettori che sopraggiungono hanno diritto di prelazione rispetto ad eventuali processi scrittori già in attesa.

Finchè è attivo un processo scrittore i processi lettori devono attendere, e finquando è attivo almeno un processo scrittore tutti i processi scrittori che sopraggiungono hanno diritto di prelazione rispetto ad eventuali processi lettori già in attesa.


Semafori.H (L'implementazione è quella indicata per il programma I)


#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>


void Init_Sem(int, int); //Inizializza Semaforo


void Wait_Sem(int, int); //Wait su Semaforo


void Signal_Sem(int, int);     //Signal su Semaforo


int Awaiting_Sem(int, int);   //Restituisce il numero di processi in attesa su Semaforo


Lett_Scrit_Starv.H


#include <stdio.h>

#include"semafori.h"


typedef struct Buffer;


void Init_Buffer(Buffer*);      //Inizializza il vettore


void Init_Semafori(int);         //Inizializza i semafori


void Inizio_Lettura(Buffer*, int);                            //Acquisizione del buffer in lettura


char Lettura(Buffer*);                        //Lettura del buffer


void Fine_Lettura(Buffer*, int);                              //Rilascio del buffer dopo una lettura


void Inizio_Scrittura(Buffer*, int);                          //Acquisizione del buffer per la scrittura


void Scrittura(char, Buffer*); //Scrittura del buffer


void Fine_Scrittura(Buffer*, int);                            //Rilascio del buffer dopo una scrittura


Lett_Scrit_Starv.C


#include "Lett_Scrit_Starv.h"    


#define MUTEX_LETT 0                   //Definizione di MACRO per l'accesso ai semafori

#define MUTEX_SCRIT 1

#define MUTEX 2

#define SYNCH 3

#define INITIALIZE(S,V) Init_Sem(ID_Sem,S,V)

#define WAIT(S) Wait_Sem(ID_Sem,S)

#define SIGNAL(S) Signal_Sem(ID_Sem,S)


void Init_Buffer(Buffer* B)


void Init_Semafori(int ID_Sem)


void Inizio_Lettura(Buffer* B, int ID_Sem)


SIGNAL(MUTEX_LETT);



char Lettura(Buffer* B)



void Fine_Lettura(Buffer* B, int ID_Sem)


SIGNAL(MUTEX_LETT);



void Inizio_Scrittura(Buffer* B, int ID_Sem)


SIGNAL(MUTEX_SCRIT);


WAIT(MUTEX);



void Scrittura(char value, Buffer* B)


void Fine_Scrittura(Buffer* B, int ID_Sem)


SIGNAL(MUTEX_SCRIT);



Programma VI.C


#include <stdio.h>         

#include <sys/shm.h>     

#include <sys/wait.h>         

#include 'lett_scrit_starv.h'


#define DIM sizeof(Buffer)              //Dimensione dell'area di memoria condivisa

#define NUM_LETT 5   //Numero di processi lettori

#define NUM_SCRIT 2                                //Numero di processi scrittori


void main()


Ptr_Buf=(Buffer*)shmat(ID_Buf, 0, 0); //Il segmento allocato viene annesso al segmento dati

//del processo al primo indirizzo disponibile così come

//specificato dal sistema

if (Ptr_Buf==(Buffer*)-1)


Init_Buffer(Ptr_Buf); //Inizializzazione del Buffer


//----- CREAZIONE SEMAFORI -----


key_t Key_Sem=IPC_PRIVATE; //Chiave del semaforo/i

int ID_Sem; //Identificatore del semaforo/i


ID_Sem=semget(Key_Sem, 4, IPC_CREAT|0664); //Viene allocato un gruppo di semafori di cardinalità 4,

//viene associato al gruppo un ID e viene creata una

//struttura dati ausiliaria che consenta di gestirlo

//RW per User, RW per Gruppo, R only per Others

if (ID_Sem==-1)


Init_Semafori(ID_Sem); //Inizializzazione dei semafori


//----- GENERAZIONE FIGLI SCRITTORI -----


for(i=0; i<NUM_SCRIT; i++) {


pid=fork(); //Generazione del figlio Scrittore i-esimo

if (pid==-1) else if (!pid)


Inizio_Scrittura(Ptr_Buf, ID_Sem);

Scrittura(value, Ptr_Buf);

Fine_Scrittura(Ptr_Buf, ID_Sem);


exit(0); //Il figlio Scrittore termina correttamente

}


} //End For NUM_SCRIT


//----- GENERAZIONE FIGLI LETTORI -----


for(i=0; i<NUM_LETT; i++) {


pid=fork(); //Generazione del figlio Lettore i-esimo

if (pid==-1) else if (!pid)


} //End For NUM_LETT


//----- SINCRONIZZAZIONE DEL PADRE CON I FIGLI -----


for(i=0; i<NUM_SCRIT+NUM_LETT; i++)


//----- RILASCIO MEMORIA CONDIVISA E SEMAFORO -----


shmctl(ID_Buf, IPC_RMID, 0);

semctl(ID_Sem, 0, IPC_RMID);











Problemi di cooperazione nel modello a scambio di messaggi


VII) Scrivere una applicazione concorrente che implementi il problema Produttore/Consumatore utilizzando le primitive send e receive per la comunicazione mediante code di messaggi (Costruzione di un protocollo sincrono mediante le primitive di scambio di messaggi asincrone).


Descrizione: Il programma seguente risolve il problema dei Produttori/Consumatori implementando un protocollo sincrono di comunicazione che fa uso delle primitive (asincrone) messe a disposizione dal sistema. Occorre fare in modo che produttore e consumatore si sincronizzino opportunamente in modo da non perdere il messaggio da scambiare. A tal fine produttore e consumatore, prima dell'invio del messaggio effettivo, si scambiano dei messaggi di sincronizzazione secondo lo schema seguente


Produttore Consumatore

Invia messaggio di pronto ad inviare             In attesa di messaggio di pronto ad inviare

In attesa di messaggio di pronto a ricevere Invio messaggio di pronto a ricevere

Invio del messaggio effettivo                         In attesa del messaggio effettivo


Ovvero, in termini di Send Asincrona a Receive Bloccante

Produttore Consumatore

Send asincrona(coda, "pronto ad inviare") Receive bloccante(coda, pronto ad inviare)

Receive bloccante(coda, pronto a ricevere) Send asincrona(coda, "pronto a ricevere")

Send asincrona(coda, "messaggio")   Receive bloccante(coda, messaggio)


Nell'implementazione proposta viene utilizzata una sola coda differenziando nel contempo il tipo di messaggi.


Programma VII.C


#include <sys/types.h>

#include <stdio.h>         

#include <sys/ipc.h>

#include <sys/msg.h>

#include <sys/wait.h>


#define DIM_MSG 256                      //Cardinalità del Messaggio

#define Ready_To_Send 0      //Tipi di Messaggio

#define Ready_To_Receive 1

#define Data_Message 2


typedef struct Messaggio;


void main()


//----- GENERAZIONE FIGLIO PRODUTTORE -----


pid=fork(); //Generazione del figlio Produttore

if (pid==-1) else if (!pid)


exit(0); //Il figlio Produttore termina correttamente

}


//----- GENERAZIONE FIGLIO CONSUMATORE -----


pid=fork(); //Generazione del figlio Consumatore

if (pid==-1) else if (!pid)


exit(0); //Il figlio Consumatore termina correttamente

}


//----- SINCRONIZZAZIONE DEL PADRE CON I FIGLI -----


for(i=0; i<2; i++)


//----- RILASCIO CODA DI MESSAGGI -----


msgctl(ID_Msg, IPC_RMID, 0);































































Problemi di cooperazione nel modello a scambio di messaggi


VIII) Scrivere una applicazione concorrente che implementi uno schedulatore di processi che gestisce tre livelli di priorità usando le code di messaggi.


Descrizione: Il programma seguente mostra come è possibile implementare uno schedulatore di processi usando le code di messaggi. Un processo utente che voglia essere schedulato deve inviare allo schedulatore un messaggio di tipo Ready_To_Be_Scheduled, indicando in esso la propria priorità e il proprio PID, dopodiché si pone in attesa, da parte dello schedulatore, di un messaggio di tipo Ready_To_Schedule_You che gli comunichi che è stato scelto: a questo punto il processo eseguirà il suo carico di istruzioni e prima di terminare invierà allo scheduler un messaggio di tipo End_of_Execute, segnalando in tal modo di aver concluso il proprio lavoro. Più in generale, lo scheduler esegue ciclicamente il polling (receive non bloccante) di una coda dei messaggi (si è scelto per semplicità di usare una sola coda) alla ricerca di una richiesta di schedulazione, analizzando le richieste disponibili sulla base della priorità dichiarata dai singoli processi e scegliendo il prossimo processo da schedulare: letto il PID del messaggio prescelto, gli viene inviato un messaggio di attivazione. Fatto ciò, non gli resta che porsi in attesa della segnalazione di terminazione del processo schedulato, dopo la quale potrà riprendere a svolgere da capo la propria attività. Si noti che, nell'implementazione proposta, il processo padre è lo scheduler dei processi figli.


Programma VIII.C


#include <sys/types.h>

#include <stdio.h>         

#include <sys/ipc.h>

#include <sys/msg.h>

#include <sys/wait.h>


#define DIM_MSG (sizeof(unsigned int))               //Cardinalità del Messaggio

#define Urgent 0                     //Tipi del Messaggio

#define Normal 1

#define Idle 2

#define End_of_Execute 3

#define Ready_To_Schedule_You (long)100000


typedef struct Messaggio;


#define N_PROC 5                 //Numero di processi da schedulare


void main()




//----- GENERAZIONE DEI FIGLI DA SCHEDULARE -----


for(i=0; i<N_PROC; i++)


pid=fork(); //Generazione del figlio i-esimo

if (pid==-1) else if (!pid)


} //End For N_PROC


//----- SCHEDULAZIONE DEI FIGLI -----


for (i=0; i<N_PROC; i++) //Almeno un processo ha richiesto

//la schedulazione


printf('Mando in esecuzione il processo con PID %d e priorità %dn', msg.PID, priority);

msg.tipo = msg.PID + Ready_To_Schedule_You;

msgsnd(ID_Msg, (const void*)&msg, DIM_MSG, 0); //Avvia l'esecuzione del processo

//appena schedulato


msgrcv(ID_Msg, (const void*)&msg, DIM_MSG, End_of_Execute, 0); //Rimane in attesa che tale

//processo schedulato gli comunichi

//la sua terminazione

}


//----- SINCRONIZZAZIONE DEL PADRE CON I FIGLI (ormai Zombie) -----


for(i=0; i<N_PROC; i++) pid=wait(&status); //I figli sono già terminati tutti e

//sono attualmente Zombie


//----- RILASCIO CODA DI MESSAGGI -----


msgctl(ID_Msg, IPC_RMID, 0);

































































Problemi di cooperazione nel modello a scambio di messaggi


IX) Si realizzi un processo che riceve messaggi da altri processi mediante una coda di messaggi e risponde con un intero che dice quanti messaggi sono stati ricevuti fino a quel momento. Per la comunicazione delle risposte si deve usare la stessa coda di messaggi delle richieste. La coda di messaggi deve essere creata dal primo processo che ne fa uso, non necessariamente il servente.


Descrizione: Il programma seguente mostra come è possibile implementare una comunicazione multidirezionale tra processi utilizzando una singola coda di messaggi. Il processo padre genera un certo numero di processi figli:  tra questi viene casualmente designato un processo server mentre tutti gli altri divengono client. Il primo (fra tutti i processi figli) che entra in azione (dopo un tempo casuale) alloca la coda di messaggi e gli altri si limitano ad usarla. Inoltre, ciascun processo client invia un messaggio di HELLO sulla coda e attende una risposta dal server, affinchè gli comunichi quanti messaggi sono stati fino a quel momento inviati sulla coda, dopodichè termina. Il processo server attende al massimo che tutti i processi clienti abbiano inviato un messaggio a testa, dopodichè termina. Per la precisione, se ad allocare la coda è stato il server si occuperà personalmente di deallocarla prima di terminare, altrimenti ci penserà il client allocatore subito dopo aver ricevuto un segnale di cessata attività da parte del server. Si noti che il processo padre non ha alcun ruolo, se non quello di generare i processi clienti e il processo server.


Programma IX.C


#include <sys/types.h>

#include <stdio.h>         

#include <sys/ipc.h>

#include <sys/msg.h>

#include <sys/wait.h>


#define DIM_MSG (2*sizeof(unsigned int)) //Cardinalità del Messaggio

#define HELLO 0                    //Tipi del Messaggio

#define STOP 1

#define ACK (long)100000


typedef struct Messaggio;


#define N_PROC 10               //Numero totale di processi coinvolti, escluso il padre

//Di questi N_PROC, (N_PROC-1) saranno processo clienti


void main() {


pid_t pid; //Variabili locali

int i;

int status, myPID;


Messaggio msg;


//----- CHI SARA' IL PROCESSO SERVER? -----


int server=int(rand()) % N_PROC;


//----- CHI ALLOCHERA' LA CODA DI MESSAGGI? -----


int allocatore;


//----- GENERAZIONE DEI FIGLI -----


for(i=0; i<N_PROC; i++)


pid=fork(); //Generazione del figlio i-esimo

if (pid==-1) else if (!pid)

}


//----- COMPORTAMENTO DA CLIENT -----


if (i!=server)


exit(0); //Il figlio Client termina correttamente


//----- COMPORTAMENTO DA SERVER -----


} else


if (allocatore==myPID) else


exit(0); //Il figlio Server termina correttamente

}


}


} //End For N_PROC


//----- SINCRONIZZAZIONE DEL PADRE CON I FIGLI -----


for(i=0; i<N_PROC; i++)





Impiego del costrutto monitor


X) Si implementi il problema dei lettori/scrittori utilizzando il costrutto monitor.


Descrizione: Il costrutto monitor rappresenta un meccanismo di alto livello per implementare una risorsa gestore. In generale occorre definire, oltre alla risorsa da gestire, una struttura dati supplementare che contenga informazioni sullo stato della risorsa gestita. Una o più variabili di tipo condition vengono poi utilizzate per bloccare o sbloccare selettivamente i processi che competono per il controllo della risorsa, ciascuno in funzione della verifica (o meno) di una opportuna condizione di sincronizzazione. Il programma seguente implementa il problema dei lettori/scrittori evitando che l'una o l'altra categoria di processi possa andare in starvation:

  • Ogni processo che voglia accedere al monitor deve farlo in mutua esclusione con gli altri processi.
  • Un lettore che voglia leggere il contenuto del buffer di memoria condivisa (non deve farlo in mutua esclusione con gli altri lettori!) rimane in attesa sulla variabile condition SOSPESI_LETTORI solo nel caso in cui vi siano scrittori attivi o scrittori già in attesa.
  • Uno scrittore che voglia scrivere sul buffer rimane in attesa sulla variabile condition SOSPESI_SCRITTORI solo se vi sono lettori attivi o scrittori attivi.
  • Quando un lettore riesce ad ottenere l'accesso al buffer, tutti gli altri in attesa passano a valanga.
  • Uno scrittore che riesca ad ottenere l'accesso al buffer, una volta terminata la scrittura, sblocca tutti gli eventuali lettori in attesa.

Semafori.H (L'implementazione è quella indicata per il programma I)


#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>


void Init_Sem(int, int); //Inizializza Semaforo


void Wait_Sem(int, int); //Wait su Semaforo


void Signal_Sem(int, int);     //Signal su Semaforo


int Awaiting_Sem(int, int);   //Restituisce il numero di processi in attesa su Semaforo


Monitor.H


#include <stdio.h>

#include <sys/wait.h>

#include "semafori.h"


typedef struct Monitor;

//Definizione di MACRO per l'accesso ai semafori del Monitor

#define MUTEX 0                  //Il primo semaforo è sempre il Mutex

#define INITIALIZE(M,S,V) Init_Sem(M->ID_Sem,S,V)

#define WAIT(M,S) Wait_Sem(M->ID_Sem,S)

#define SIGNAL(M,S) Signal_Sem(M->ID_Sem,S)

#define AWAITING(M,S) Awaiting_Sem(M->ID_Sem,S)

#define ENTER_MONITOR(M) WAIT(M,MUTEX)                     //Implementazione della Entry

#define LEAVE_MONITOR(M) SIGNAL(M,MUTEX)


void Create_Monitor(Monitor*, int);                                  //Semaforo Mutex e variabili Conditions vengono allocati


void Destroy_Monitor(Monitor*);                           //Semaforo Mutex e variabili Conditions vengono deallocati


void Wait_Cond(Monitor*, int);                              //Emula la Wait su una variabile Condition


void Signal_Cond(Monitor*, int);                            //Emula la Signal su una variabile Condition


Monitor.C


#include "monitor.c"


void Create_Monitor(Monitor* M, int N_Conditions)



void Destroy_Monitor(Monitor* M)


void Wait_Cond(Monitor* M, int ConditionID)


void Signal_Cond(Monitor* M, int ConditionID)


Lett_Scrit_Monitor.H


#include "monitor.h"


typedef struct Buffer;


void Init_Buffer(Buffer*);      //Inizializza il Buffer


void Start_Monitor(Monitor*);          //Inizializza il Monitor


void Stop_Monitor(Monitor*);          //Elimina il Monitor


void Inizio_Lettura(Monitor*, Buffer*);                 //Acquisizione del buffer in lettura


char Lettura(Buffer*);                        //Lettura del buffer


void Fine_Lettura(Monitor*, Buffer*);                   //Rilascio del buffer dopo una lettura


void Inizio_Scrittura(Monitor*, Buffer*);               //Acquisizione del buffer per la scrittura


void Scrittura(char, Buffer*); //Scrittura del buffer


void Fine_Scrittura(Monitor*, Buffer*);                 //Rilascio del buffer dopo una scrittura


Lett_Scrit_Monitor.C


#include "lett_scritt_monitor.h"


#define SOSPESI_LETTORI 1

#define SOSPESI_SCRITTORI 2


int Lettori_Sospesi;


void Init_Buffer(Buffer* B)


void Start_Monitor(Monitor* M)


void Stop_Monitor(Monitor* M)


void Inizio_Lettura(Monitor* M, Buffer* B)


char Lettura(Buffer* B)


void Fine_Lettura(Monitor* M, Buffer* B)


void Inizio_Scrittura(Monitor* M, Buffer* B)


void Scrittura(char value, Buffer* B)


void Fine_Scrittura(Monitor* M, Buffer* B)


Programma X.C


#include "lett_scrit_monitor.h"


#define DIM sizeof(Buffer)              //Dimensione dell'area di memoria condivisa

#define NUM_LETT 5   //Numero di processi lettori

#define NUM_SCRIT 5                                //Numero di processi scrittori


void main()


Ptr_Buf=(Buffer*)shmat(ID_Buf, 0, 0); //Il segmento allocato viene annesso al segmento dati

//del processo al primo indirizzo disponibile così come

//specificato dal sistema

if (Ptr_Buf==(Buffer*)-1)


Init_Buffer(Ptr_Buf); //Inizializzazione del Buffer


//----- CREAZIONE DEL MONITOR -----


Monitor M;


Start_Monitor(&M);


//----- GENERAZIONE FIGLI SCRITTORI -----


for(i=0; i<NUM_SCRIT; i++) {


pid=fork(); //Generazione del figlio Scrittore i-esimo

if (pid==-1) else if (!pid)


Inizio_Scrittura(&M, Ptr_Buf);

Scrittura(value, Ptr_Buf);

Fine_Scrittura(&M, Ptr_Buf);


exit(0); //Il figlio Scrittore termina correttamente

}


} //End For NUM_SCRIT


//----- GENERAZIONE FIGLI LETTORI -----


for(i=0; i<NUM_LETT; i++) {


pid=fork(); //Generazione del figlio Lettore i-esimo

if (pid==-1) else if (!pid)


} //End For NUM_LETT


//----- SINCRONIZZAZIONE DEL PADRE CON I FIGLI -----


for(i=0; i<NUM_SCRIT+NUM_LETT; i++)


//----- DISTRUZIONE DEL MONITOR -----


Stop_Monitor(&M);


//----- RILASCIO BUFFER DI MEMORIA CONDIVISA -----


shmctl(ID_Buf, IPC_RMID, 0);
























































































Impiego del costrutto monitor


XI) Si implementi il problema dei produttori/consumatori utilizzando il costrutto monitor.


Descrizione: Il costrutto monitor rappresenta un meccanismo di alto livello per implementare una risorsa gestore. In generale occorre definire, oltre alla risorsa da gestire, una struttura dati supplementare che contenga informazioni sullo stato della risorsa gestita. Una o più variabili di tipo condition vengono poi utilizzate per bloccare o sbloccare selettivamente i processi che competono per il controllo della risorsa, ciascuno in funzione della verifica (o meno) di una opportuna condizione di sincronizzazione. Il programma seguente implementa il problema dei produttori/consumatori:

  • Un produttore che voglia scrivere un contenuto nel buffer di memoria condivisa deve farlo in mutua esclusione con gli altri produttori.
  • Un consumatore che voglia prelevare un contenuto dal buffer di memoria condivisa deve farlo in mutua esclusione con gli altri consumatori.
  • Quando un produttore riesce ad ottenere l'accesso al buffer, dopo avervi depositato un contenuto, sblocca uno dei consumatori eventualmente in attesa.
  • Quando un consumatore riesce ad ottenere l'accesso al buffer, una volta prelevatone il contenuto, sblocca uno dei produttori eventualmente in attesa.

Semafori.H (L'implementazione è quella indicata per il programma I)


#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>


void Init_Sem(int, int); //Inizializza Semaforo


void Wait_Sem(int, int); //Wait su Semaforo


void Signal_Sem(int, int);     //Signal su Semaforo


int Awaiting_Sem(int, int);   //Restituisce il numero di processi in attesa su Semaforo


Monitor.H (L'implementazione è quella indicata per il programma IX)


#include <stdio.h>

#include <sys/wait.h>

#include "semafori.h"


typedef struct Monitor;

//Definizione di MACRO per l'accesso ai semafori del Monitor

#define MUTEX 0                  //Il primo semaforo è sempre il Mutex

#define INITIALIZE(M,S,V) Init_Sem(M->ID_Sem,S,V)

#define WAIT(M,S) Wait_Sem(M->ID_Sem,S)

#define SIGNAL(M,S) Signal_Sem(M->ID_Sem,S)

#define AWAITING(M,S) Awaiting_Sem(M->ID_Sem,S)

#define ENTER_MONITOR(M) WAIT(M,MUTEX)                     //Implementazione della Entry

#define LEAVE_MONITOR(M) SIGNAL(M,MUTEX)


void Create_Monitor(Monitor*, int);                                  //Semaforo Mutex e variabili Conditions vengono allocati


void Destroy_Monitor(Monitor*);   //Semaforo Mutex e variabili Conditions vengono deallocati


void Wait_Cond(Monitor*, int);                              //Emula la Wait su una variabile Condition


void Signal_Cond(Monitor*, int);                            //Emula la Signal su una variabile Condition


Prod_Cons_Monitor.H


#include "monitor.h"


#define DIM_QUEUE 4          //Cardinalità del Buffer (Coda circolare)

#define VUOTO 0       //Stati del singolo buffer della Coda circolare

#define IN_USO 1

#define PIENO 2


typedef struct Buffer;


void Init_Buffer(Buffer*);      //Inizializza il Buffer


void Start_Monitor(Monitor*);          //Inizializza il Monitor


void Stop_Monitor(Monitor*);          //Elimina il Monitor


int Inizio_Consumo(Monitor*, Buffer*);                //Acquisizione di un buffer per consumo


char Consumo(int, Buffer*);  //Consumo di un buffer


void Fine_Consumo(int, Monitor*, Buffer*);                     //Rilascio del buffer dopo un consumo


int Inizio_Produzione(Monitor*, Buffer*); //Acquisizione del buffer per la produzione


void Produzione(int, char, Buffer*);                        //Produzione di un buffer


void Fine_Produzione(int, Monitor*, Buffer*);      //Rilascio del buffer dopo la produzione


Prod_Cons_Monitor.C


#include "lett_scritt_monitor.h"


#define SOSPESI_CONSUMATORI 1

#define SOSPESI_PRODUTTORI 2


void Init_Buffer(Buffer* B)


void Start_Monitor(Monitor* M)


void Stop_Monitor(Monitor* M)


int Inizio_Consumo(Monitor* M, Buffer* B)

if (i==B->testa) B->testa=(B->testa+1) % DIM_QUEUE;

B->stato[i]=IN_USO;


LEAVE_MONITOR(M);

return i;



char Consumo(int i, Buffer* B)


void Fine_Consumo(int i, Monitor* M, Buffer* B)


int Inizio_Produzione(Monitor* M, Buffer* B) while (B->stato[B->coda]!=VUOTO);

B->stato[i]=IN_USO;


LEAVE_MONITOR(M);

return i;



void Produzione(int i, char value, Buffer* B)


void Fine_Produzione(int i, Monitor* M, Buffer* B)


Programma XI.C


#include 'prod_cons_monitor.h'


#define DIM sizeof(Buffer)              //Dimensione dell'area di memoria condivisa

#define NUM_PROD 3    //Numero di processi produttori

#define NUM_PRODUZ 5     //Numero di produzioni per ogni processo produttore

#define NUM_CONS 5     //Numero di processi consumatori

#define NUM_CONSUM 3     //Numero di consumi per ogni processo consumatore


void main()


Ptr_Buf=(Buffer*)shmat(ID_Buf, 0, 0); //Il segmento allocato viene annesso al segmento dati

//del processo al primo indirizzo disponibile così come

//specificato dal sistema

if (Ptr_Buf==(Buffer*)-1)


Init_Buffer(Ptr_Buf); //Inizializzazione del Buffer


//----- CREAZIONE DEL MONITOR -----


Monitor M;


Start_Monitor(&M);


//----- GENERAZIONE FIGLI PRODUTTORI -----


for(i=0; i<NUM_PROD; i++) {


pid=fork(); //Generazione del figlio Produttore i-esimo

if (pid==-1) else if (!pid)


exit(0); //Il figlio Produttore termina correttamente

}


} //End For NUM_PROD


//----- GENERAZIONE FIGLI CONSUMATORI -----


for(i=0; i<NUM_CONS; i++) {


pid=fork(); //Generazione del figlio Consumatore i-esimo

if (pid==-1) else if (!pid)


exit(0); //Il figlio Consumatore termina correttamente

}


} //End For NUM_CONS


//----- SINCRONIZZAZIONE DEL PADRE CON I FIGLI -----


for(i=0; i<NUM_PROD+NUM_CONS; i++)


//----- DISTRUZIONE DEL MONITOR -----


Stop_Monitor(&M);


//----- RILASCIO BUFFER DI MEMORIA CONDIVISA -----


shmctl(ID_Buf, IPC_RMID, 0);











Impiego del costrutto monitor


XII) Scrivere una applicazione concorrente che implementi mediante un monitor il problema della gestione di un'unità a disco a teste mobili (secondo l'algoritmo dell'ascensore).


Descrizione: Il costrutto monitor rappresenta un meccanismo di alto livello per implementare una risorsa gestore. In generale occorre definire, oltre alla risorsa da gestire, una struttura dati supplementare che contenga informazioni sullo stato della risorsa gestita. Una o più variabili di tipo condition vengono poi utilizzate per bloccare o sbloccare selettivamente i processi che competono per il controllo della risorsa, ciascuno in funzione della verifica (o meno) di una opportuna condizione di sincronizzazione. Nel caso specifico, la libreria Monitor usata nei programmi precedenti è stata leggermente modificata in modo da supportare l'uso di una Wait con Priorità (è possibile comunque non specificare alcuna priorità, in tal caso la Wait su Condition si comporta esattamente come in un monitor senza priorità). Il programma seguente implementa il problema della gestione di un'unità a disco a testine mobili secondo l'algoritmo dello SCAN (altrimenti detto dell'Ascensore): il disco viene percorso da un estremo all'altro nelle direzioni SU (dalla traccia più esterna a quella più interna) e GIU (dalla traccia più interna a quella più esterna) e vengono servite le richieste di accesso al disco nell'ordine in cui si incontrano muovendosi lungo la direzione corrente; arrivati ad un estremo si inverte la direzione. Per ottimizzare le operazioni, si è inoltre fatto in modo che la direzione venga invertita qualora non si abbiano altre richieste di servizio nella direzione di percorrenza corrente (algoritmo LOOK). Si noti che per evitare il fenomeno della starvation non vengono servite richieste supplementari (rispetto alla prima) relative ad una traccia che si sta già servendo.




PMonitor.H


#include <stdio.h>

#include <sys/wait.h>

#include "semafori.h"


#define MAX_PROC (long)10           //Numero massimo di processi in coda su ogni Condition


typedef struct Monitor;

//Definizione di MACRO per l'accesso ai semafori del Monitor

#define MUTEX 0                  //Il primo semaforo è sempre il Mutex

#define INITIALIZE(M,S,V) Init_Sem(M->ID_Sem,S,V)

#define WAIT(M,S) Wait_Sem(M->ID_Sem,S)

#define SIGNAL(M,S) Signal_Sem(M->ID_Sem,S)

#define AWAITING(M,S) Awaiting_Sem(M->ID_Sem,S)

#define ENTER_MONITOR(M) WAIT(M,MUTEX)                     //Implementazione della Entry

#define LEAVE_MONITOR(M) SIGNAL(M,MUTEX)


void Create_Monitor(Monitor*, int);                                  //Semaforo Mutex e variabili Conditions vengono allocati


void Destroy_Monitor(Monitor*);                           //Semaforo Mutex e variabili Conditions vengono deallocati


void Wait_Cond(Monitor*, int, int = 1);                 //Emula la Wait (con priorità) su una variabile Condition


void Signal_Cond(Monitor*, int);                            //Emula la Signal su una variabile Condition


PMonitor.C


#include "pmonitor.c"


void Create_Monitor(Monitor* M, int N_Conditions)


M->Priority=(int*)shmat(ID_Buf, 0, 0); //Il segmento allocato viene annesso al segmento dati

//del processo al primo indirizzo disponibile così come

//specificato dal sistema

if (M->Priority==(int*)-1)


//Priority è gestito come una coda di priorità: ogni volta che un processo si pone in attesa sul Monitor, //aggancia a questo vettore la sua priorità. Il Monitor poi provvede a riordinarne in modo crescente gli

//elementi in modo che in coda a Priority ci sia sempre la priorità più alta (minimo 1)


for(int i=0; i<N_Conditions; i++) Priority[i*MAX_PROC]=i*MAX_PROC;


//In Priority[i*MAX_PROC] c'è il puntatore all'ultimo elemento del segmento i-esimo del vettore, ovvero

//il segmento che si riferisce alla (i+1)esima variabile condition


key_t Key_Sem=IPC_PRIVATE; //Chiave del gruppo di semafori


M->ID_Sem=semget(Key_Sem, N_Conditions+1, IPC_CREAT|0664);


if (M->ID_Sem==-1)



void Destroy_Monitor(Monitor* M)


void Wait_Cond(Monitor* M, int ConditionID, int P)


//Se il processo arriva QUI significa che è quello a priorità massima!


M->Priority[Zero]--; //e cancella la sua priorità da Priority



void Signal_Cond(Monitor* M, int ConditionID)


LOOK.H


#include "pmonitor.h"


#define TRACCE (long)1000


enum DIREZIONE ;


typedef struct Ascensore;


void Init_Ascensore(Ascensore*);                           //Inizializza l'Ascensore


void Start_Monitor(Monitor*);          //Inizializza il Monitor


void Stop_Monitor(Monitor*);          //Elimina il Monitor


void Richiesta(int, Monitor*, Ascensore*); //Richiesta di accesso al disco


void Accesso(int, Ascensore*);                                //Accesso ad una traccia


void Rilascio(Monitor*, Ascensore*);                                 //Rilascio del disco


LOOK.C


#include "look.h"


#define DIREZIONE_SU 1

#define DIREZIONE_GIU 2


void Init_Ascensore(Ascensore* A)


void Start_Monitor(Monitor* M)


void Stop_Monitor(Monitor* M)


void Richiesta(int destinazione, Monitor* M, Ascensore* A)


void Accesso(int destinazione, Ascensore* A)


void Rilascio(Monitor* M, Ascensore* A)


} else

}



Programma XII.C


#include "look.h"


#define DIM sizeof(Ascensore)                    //Dimensione dell'area di memoria condivisa

#define NUM_PROC 10   //Numero di processi che eseguono accessi


void main()


Ptr_Buf=(Ascensore*)shmat(ID_Buf, 0, 0); //Il segmento allocato viene annesso al segmento dati

//del processo al primo indirizzo disponibile così come

//specificato dal sistema

if (Ptr_Buf==(Ascensore*)-1)


Init_Ascensore(Ptr_Buf); //Inizializzazione dell'Ascensore


//----- CREAZIONE DEL MONITOR -----


Monitor M;


Start_Monitor(&M);


//----- GENERAZIONE FIGLI CHE PRODUCONO GLI ACCESSI -----


for(i=0; i<NUM_PROC; i++) {


pid=fork(); //Generazione del figlio i-esimo

if (pid==-1) else if (!pid)


} //End For NUM_PROC


//----- SINCRONIZZAZIONE DEL PADRE CON I FIGLI -----


for(i=0; i<NUM_PROC; i++)


//----- DISTRUZIONE DEL MONITOR -----


Stop_Monitor(&M);


//----- RILASCIO BUFFER DI MEMORIA CONDIVISA -----


shmctl(ID_Buf, IPC_RMID, 0);



























































































Impiego di file


XIII) Si realizzino due processi che interagiscono tramite memoria comune al fine di leggere dati da un disco. Il primo legge da disco blocchi di dati e li deposita in un insieme di buffer allocati in memoria comune. Il secondo processo stampa a video tutto ciò che trova in tali buffer.


Descrizione: Il programma presentato è un tipico esempio di cooperazione tra processi  pertanto si è scelto di realizzarlo facendo riferimento al problema Produttori/Consumatori, con uso di un buffer multiplo di memoria comune, e facendo sincronizzare i due processi mediante scambio di messaggi. In pratica, il processo che legge i dati dal disco per poi depositarli nel buffer di memoria condivisa funge da produttore, mentre il processo che legge i dati dal buffer e li stampa a video funge da consumatore. I due processi interagiscono come segue:

Il produttore legge un blocco dati alla volta dal file finquando non ne viene raggiunta la fine.

Ad ogni lettura, il produttore deposita il blocco dati nel buffer di memoria comune, invia al consumatore una messaggio di SENT (Send Asincrona) con cui lo informa che un blocco dati è disponibile e si mette in attesa di un ACK da parte del consumatore (fondamentale perchè alla prossima lettura il contenuto del buffer sarà sovrascritto e finchè il consumatore non ha ricevuto il blocco dati corrente nessun'altra lettura è possibile).

Il consumatore è perennemente in attesa (Receive Bloccante) che un blocco dati sia disponibile, quando lo riceve ne stampa il contenuto a video e dopo invia l'ACK al produttore.

Quando il produttore è giunto (in lettura) alla fine del file, comunica al consumatore questa circostanza, il consumatore stampa a video un messaggio che segnala la fine delle operazioni ed entrambi terminano.


Programma XIII.C


#include <sys/types.h>

#include <stdio.h>         

#include <sys/ipc.h>

#include <sys/msg.h>

#include <sys/wait.h>

#include <fcntl.h>


#define DIM 256                     //Dimensione del Buffer condiviso

#define DIM_MSG (sizeof(unsigned int))               //Cardinalità del Messaggio

#define SENT 0                                  //Tipi del Messaggio

#define ACK 1


typedef struct Messaggio;


void main()


//----- ALLOCAZIONE BUFFER DI MEMORIA CONDIVISA -----


key_t Key_Buf=IPC_PRIVATE; //Chiave del buffer

int ID_Buf; //Identificatore del buffer

char* Ptr_Buf; //Puntatore al buffer


ID_Buf=shmget(Key_Buf, DIM, IPC_CREAT|0664); //Viene allocato un segmento di memoria di dimensione almeno

//pari DIM, gli viene associato un ID e viene creata una

//struttura dati ausiliaria che consenta di gestirlo

//RW per User, RW per Gruppo, R only per Others

if (ID_Buf==-1)


Ptr_Buf=shmat(ID_Buf, 0, 0); //Il segmento allocato viene annesso al segmento dati

//del processo al primo indirizzo disponibile così come

//specificato dal sistema

if (Ptr_Buf==(char*)-1)


//----- GENERAZIONE DEL FIGLIO PRODUTTORE -----


pid=fork(); //Generazione del figlio Produttore

if (pid==-1) else if (!pid)


do


if (N_Byte>=0)


//Rimane in attesa di un messaggio dal Consumatore


msgrcv(ID_Msg, (const void*)&msg, DIM_MSG, ACK, 0);


} while(N_Byte==DIM-1); //in caso contrario, con l'ultimo

//trasferimento si è raggiunto l'EOF


close(fd);                                 //Chiusura del file


exit(0); //Il figlio Produttore termina correttamente

}


//----- GENERAZIONE DEL FIGLIO CONSUMATORE -----


pid=fork(); //Generazione del figlio Consumatore

if (pid==-1) else if (!pid) else

}

}


exit(0); //Il figlio Consumatore termina correttamente

}


//----- SINCRONIZZAZIONE DEL PADRE CON I FIGLI -----


for(i=0; i<2; i++)


//----- RILASCIO BUFFER E CODA DI MESSAGGI -----


shmctl(ID_Buf, IPC_RMID, 0);


msgctl(ID_Msg, IPC_RMID, 0);


























































































Impiego di file


XIV) Si realizzino due processi che interagiscono tramite memoria comune al fine di duplicare dati da un disco. Il primo legge da disco blocchi di dati e li deposita in un insieme di buffer allocati in memoria comune. Il secondo processo crea un secondo file e vi scrive ciò che trova in tali buffer.


Descrizione: Il programma presentato è un tipico esempio di cooperazione tra processi pertanto si è scelto di realizzarlo facendo riferimento al problema Produttori/Consumatori, con uso di un buffer multiplo di memoria comune, e facendo sincronizzare i due processi mediante scambio di messaggi. In pratica, il processo che legge i dati dal disco per poi depositarli nel buffer di memoria condivisa funge da produttore, mentre il processo che legge i dati dal buffer e li deposita in un nuovo file funge da consumatore. I due processi interagiscono come segue:

Il produttore legge un blocco dati alla volta dal file finquando non ne viene raggiunta la fine.

Ad ogni lettura, il produttore deposita il blocco dati nel buffer di memoria comune, invia al consumatore una messaggio di SENT (Send Asincrona) con cui lo informa che un blocco dati è disponibile e si mette in attesa di un ACK da parte del consumatore (fondamentale perchè alla prossima lettura il contenuto del buffer sarà sovrascritto e finchè il consumatore non ha ricevuto il blocco dati corrente nessun'altra lettura è possibile).

Il consumatore è perennemente in attesa (Receive Bloccante) che un blocco dati sia disponibile, quando lo riceve lo invia in scrittura all'interno di un nuovo file (da esso inizialmente aperto) e dopo invia l'ACK al produttore.

Quando il produttore è giunto (in lettura) alla fine del file, comunica al consumatore questa circostanza, il consumatore stampa a video un messaggio che segnala la fine delle operazioni ed entrambi terminano.


Programma XIV.C


#include <sys/types.h>

#include <stdio.h>         

#include <sys/ipc.h>

#include <sys/msg.h>

#include <sys/wait.h>

#include <fcntl.h>


#define DIM 256                     //Dimensione del Buffer condiviso

#define DIM_MSG (sizeof(unsigned int))               //Cardinalità del Messaggio

#define SENT 0                                  //Tipi del Messaggio

#define ACK 1


typedef struct Messaggio;


void main()


//----- ALLOCAZIONE BUFFER DI MEMORIA CONDIVISA -----


key_t Key_Buf=IPC_PRIVATE; //Chiave del buffer

int ID_Buf; //Identificatore del buffer

char* Ptr_Buf; //Puntatore al buffer


ID_Buf=shmget(Key_Buf, DIM, IPC_CREAT|0664); //Viene allocato un segmento di memoria di dimensione almeno

//pari DIM, gli viene associato un ID e viene creata una

//struttura dati ausiliaria che consenta di gestirlo

//RW per User, RW per Gruppo, R only per Others

if (ID_Buf==-1)


Ptr_Buf=shmat(ID_Buf, 0, 0); //Il segmento allocato viene annesso al segmento dati

//del processo al primo indirizzo disponibile così come

//specificato dal sistema

if (Ptr_Buf==(char*)-1)


//----- GENERAZIONE DEL FIGLIO PRODUTTORE -----


pid=fork(); //Generazione del figlio Produttore

if (pid==-1) else if (!pid)


do


if (N_Byte>=0)


//Rimane in attesa di un messaggio di ACK dal Consumatore


msgrcv(ID_Msg, (const void*)&msg, DIM_MSG, ACK, 0);


if (msg.count<0)


} while(N_Byte==DIM-1); //in caso contrario, con l'ultimo

//trasferimento si è raggiunto l'EOF


close(fd);                                 //Chiusura del file


exit(0); //Il figlio Produttore termina correttamente

}


//----- GENERAZIONE DEL FIGLIO CONSUMATORE -----


pid=fork(); //Generazione del figlio Consumatore

if (pid==-1) else if (!pid)


//Ciclo bloccante di lettura dalla coda di messaggi


while(true) else



if (msg.count<DIM-1)

}


} //END of WHILE


close(fd);                                 //Chiusura del file


exit(0); //Il figlio Consumatore termina correttamente

}


//----- SINCRONIZZAZIONE DEL PADRE CON I FIGLI -----


for(i=0; i<2; i++)


//----- RILASCIO BUFFER E CODA DI MESSAGGI -----


shmctl(ID_Buf, IPC_RMID, 0);

msgctl(ID_Msg, IPC_RMID, 0);
























Scarica gratis Problemi di mutua esclusione nel modello a memoria comune
Appunti su:











Scarica 100% gratis e , tesine, riassunti



Registrati ora

Password dimenticata?
  • Appunti superiori
  • In questa sezione troverai sunti esame, dispense, appunti universitari, esercitazioni e tesi, suddivisi per le principali facoltà.
  • Università
  • Appunti, dispense, esercitazioni, riassunti direttamente dalla tua aula Universitaria
  • all'Informatica
  • Introduzione all'Informatica, Information and Comunication Tecnology, componenti del computer, software, hardware ...