Che materia stai cercando?

Anteprima

ESTRATTO DOCUMENTO

Problemi di cooperazione nel modello a memoria comune

Scrivere una applicazione concorrente che implementi il problema

II)

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:

• consumo processo consumatore

il del buffer di memoria comune (allocato dal processo padre) da parte del

processo produttore contenuto,

non può avvenire se non dopo che il vi abbia depositato un e all'atto

consumo contenuto

del tale viene cancellato.

• processo produttore contenuto

il non può depositare nel buffer di memoria comune un nuovo se il

precedente non è stato ancora consumato.

• processo consumatore processo

A garanzia della consistenza del contenuto del buffer condiviso, e

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() {

pid_t pid; //Variabili locali

int i;

char value='A';

int status;

//----- 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) {

perror("SHMGET\n"); //In caso di errore...

exit(-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) {

perror("SHMAT\n"); //In caso di errore...

shmctl(ID_Buf, IPC_RMID, 0); //Rimuove l'ID della Shared Memory indicata, dealloca

//il segmento di memoria corrispondente ed elimina le

//strutture dati ad esso associate

exit(-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) {

perror("SEMGET\n"); //In caso di errore...

exit(-1);

} 4

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) {

perror("Impossibile creare un nuovo processo\n"); //In caso di errore...

exit(-1);

} else if (!pid) { //Codice del figlio Produttore

printf("Sono il Produttore, PID = %d\n", getpid());

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

WAIT(SPAZIO_DISPONIBILE);

printf("Produco: %c\n", value); //Sezione Critica di PRODUZIONE

*Ptr_Buf=value;

SIGNAL(MESSAGIO_DISPONIBILE);

value++; //Avanza nell'alfabeto

sleep(5); //Simula un tempo di produzione

}

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

}

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

pid=fork();

if (pid==-1) {

perror("Impossibile creare un nuovo processo\n"); //In caso di errore...

exit(-1);

} else if (!pid) { //Codice del figlio Consumatore

printf("Sono il Consumatore, PID = %d\n", getpid());

sleep(3); //Attende prima di tentare di consumare

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

WAIT(MESSAGIO_DISPONIBILE);

value=*Ptr_Buf; //Sezione Critica di CONSUMO

printf("Leggo: %c\n", value);

SIGNAL(SPAZIO_DISPONIBILE);

sleep(5); //Simula un tempo di consumo

}

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

}

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

for(i=0; i<2; i++) { //Il padre rimane in attesa che i figli terminino...

pid=wait(&status);

printf("Il figlio con PID %d è terminato!\n",pid);

}

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

shmctl(ID_Buf, IPC_RMID, 0);

semctl(ID_Sem, 0, IPC_RMID);

} 5

Problemi di cooperazione nel modello a memoria comune

Scrivere un’applicazione concorrente che implementi il problema

III)

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:

• consumo

il di un singolo buffer di memoria comune (l'insieme del pool è allocato dal processo padre) da

processo consumatore processo produttore

parte di un non può avvenire se non dopo che almeno un vi

contenuto, consumo contenuto

abbia depositato un e all'atto del tale viene cancellato.

• processo produttore contenuto

un non può depositare in un buffer di memoria comune un nuovo se non è

disponibile alcun buffer libero.

• processi consumatori processi

A garanzia della consistenza del contenuto del buffer condiviso, e

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 { //Definizione della Coda circolare

char buffer[DIM_QUEUE];

char stato[DIM_QUEUE]; //VUOTO, IN_USO o PIENO

int testa;

int coda;

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

for(int i=0; i<DIM_QUEUE; i++) Q->stato[i]=VUOTO;

Q->testa=0;

Q->coda=0;

}

void Init_Semafori_Queue(int ID_Sem) {

INITIALIZE(SPAZIO_DISPONIBILE,DIM_QUEUE);

INITIALIZE(MESSAGGIO_DISPONIBILE,0);

INITIALIZE(MUTEX_PROD,1);

INITIALIZE(MUTEX_CONS,1);

}

int Richiesta_Produzione_Queue(Queue* Q, int ID_Sem) {

WAIT(SPAZIO_DISPONIBILE);

WAIT(MUTEX_PROD); 6

int i=Q->coda;

do { Q->coda=(Q->coda+1) % DIM_QUEUE; } while (Q->stato[Q->coda]!=VUOTO);

Q->stato[i]=IN_USO;

SIGNAL(MUTEX_PROD);

printf("Buffer %d in uso\n", i);

return i;

}

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

Q->buffer[i]=value;

printf("Ho prodotto %c nel buffer %d\n", value, i);

}

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

Q->stato[i]=PIENO;

printf("Buffer %d riempito\n", i);

SIGNAL(MESSAGGIO_DISPONIBILE);

}

int Richiesta_Consumo_Queue(Queue* Q, int ID_Sem) {

WAIT(MESSAGGIO_DISPONIBILE);

WAIT(MUTEX_CONS);

int i=Q->testa;

while (Q->stato[i]!=PIENO) { i=(i+1) % DIM_QUEUE; }

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

Q->stato[i]=IN_USO;

SIGNAL(MUTEX_CONS);

printf("Buffer %d in uso\n", i);

return i;

}

char Consumo_Queue(int i, Queue* Q) {

char value=Q->buffer[i];

printf("Ho consumato %c nel buffer %d\n", value, i);

return value;

}

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

Q->stato[i]=VUOTO;

printf("Buffer %d rilasciato\n", i);

SIGNAL(SPAZIO_DISPONIBILE);

}

→ 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() {

pid_t pid; //Variabili locali

int i,j,k;

char value='A';

int status;

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

key_t Key_Buf=IPC_PRIVATE; //Chiave del buffer

int ID_Buf; //Identificatore del buffer

Queue* Ptr_Buf; //Puntatore al buffer

ID_Buf=shmget(Key_Buf, DIM, IPC_CREAT|0664); //Viene allocato un segmento di memoria atto a contenere

//una Queue, 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) {

perror("SHMGET\n"); //In caso di errore...

exit(-1);

}

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) {

perror("SHMAT\n"); //In caso di errore...

shmctl(ID_Buf, IPC_RMID, 0); //Rimuove l'ID della Shared Memory indicata, dealloca

//il segmento di memoria corrispondente ed elimina le

//strutture dati ad esso associate

exit(-1);

} 7

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) {

perror("SEMGET\n"); //In caso di errore...

exit(-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) {

perror("Impossibile creare un nuovo processo\n"); //In caso di errore...

exit(-1);

} else if (!pid) { //Codice del figlio Produttore

printf("Sono un Produttore, PID = %d\n", getpid());

for (j=0; j<NUM_PRODUZ; j++) {

k=Richiesta_Produzione_Queue(Ptr_Buf, ID_sem);

Produzione_Queue(k, value, Ptr_Buf);

Rilascio_Produzione_Queue(k, Ptr_Buf, ID_Sem);

value++; //Avanza nell'alfabeto

sleep(5); //Simula un tempo di produzione

}

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) {

perror("Impossibile creare un nuovo processo\n"); //In caso di errore...

exit(-1);

} else if (!pid) { //Codice del figlio Consumatore

printf("Sono un Consumatore, PID = %d\n", getpid());

sleep(3); //Attende prima di tentare di consumare

for (j=0; j<NUM_CONSUM; j++) {

k=Richiesta_Consumo_Queue(Ptr_Buf, ID_Sem);

char consumo=Consumo_Queue(k, Ptr_Buf);

Rilascio_Consumo_Queue(k, Ptr_Buf, ID_Sem);

sleep(5); //Simula un tempo di consumo

}

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++) { //Il padre rimane in attesa che i figli terminino...

pid=wait(&status);

printf("Il figlio con PID %d è terminato!\n",pid);

}

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

shmctl(ID_Buf, IPC_RMID, 0);

semctl(ID_Sem, 0, IPC_RMID);

} 8

Problemi di cooperazione nel modello a memoria comune

Scrivere una applicazione concorrente che implementi il problema

IV)

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:

• consumo

il di un singolo buffer di memoria comune (l'insieme del pool è allocato dal processo padre) da

processo consumatore processo produttore

parte di un non può avvenire se non dopo che almeno un vi

contenuto, consumo contenuto

abbia depositato un e all'atto del tale viene cancellato.

• processo produttore contenuto

un non può depositare in un buffer di memoria comune un nuovo se non è

disponibile alcun buffer libero.

• processi consumatori processi

A garanzia della consistenza del contenuto del buffer condiviso, e

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 { //Definizione del vettore

char buffer[DIM_VECTOR];

char stato[DIM_VECTOR]; //VUOTO, IN_USO o PIENO

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

for(int i=0; i<DIM_Vector; i++) V->stato[i]=VUOTO;

}

void Init_Semafori_Vector(int ID_Sem) {

INITIALIZE(SPAZIO_DISPONIBILE,DIM_VECTOR);

INITIALIZE(MESSAGGIO_DISPONIBILE,0);

INITIALIZE(MUTEX_PROD,1);

INITIALIZE(MUTEX_CONS,1);

}

int Richiesta_Produzione_Vector(Vector* V, int ID_Sem) {

WAIT(SPAZIO_DISPONIBILE);

WAIT(MUTEX_PROD);

int i=0;

while(V->stato[i]!=VUOTO) { i=(i+1) % DIM_VECTOR; }

V->stato[i]=IN_USO; 9

SIGNAL(MUTEX_PROD);

printf("Buffer %d in uso\n", i);

return i;

}

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

V->buffer[i]=value;

printf("Ho prodotto %c nel buffer %d\n", value, i);

}

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

V->stato[i]=PIENO;

printf("Buffer %d riempito\n", i);

SIGNAL(MESSAGGIO_DISPONIBILE);

}

int Richiesta_Consumo_Vector(Vector* V, int ID_Sem) {

WAIT(MESSAGGIO_DISPONIBILE);

WAIT(MUTEX_CONS);

int i=0;

while(V->stato[i]!=PIENO) { i=(i+1) % DIM_VECTOR; }

V->stato[i]=IN_USO;

SIGNAL(MUTEX_CONS);

printf("Buffer %d in uso\n", i);

return i;

}

char Consumo_Vector(int i, Vector* V) {

char value=V->buffer[i];

printf("Ho consumato %c nel buffer %d\n", value, i);

return value;

}

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

V->stato[i]=VUOTO;

printf("Buffer %d rilasciato\n", i);

SIGNAL(SPAZIO_DISPONIBILE);

}

→ 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() {

pid_t pid; //Variabili locali

int i,j,k;

char value='A', consumo;

int status;

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

key_t Key_Buf=IPC_PRIVATE; //Chiave del buffer

int ID_Buf; //Identificatore del buffer

Vector* Ptr_Buf; //Puntatore al buffer

ID_Buf=shmget(Key_Buf, DIM, IPC_CREAT|0664); //Viene allocato un segmento di memoria atto a contenere

//un Vector, 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) {

perror("SHMGET\n"); //In caso di errore...

exit(-1);

}

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) {

perror("SHMAT\n"); //In caso di errore...

shmctl(ID_Buf, IPC_RMID, 0); //Rimuove l'ID della Shared Memory indicata, dealloca

//il segmento di memoria corrispondente ed elimina le

//strutture dati ad esso associate

exit(-1);

}

Init_Vector(Ptr_Buf); //Inizializzazione del Vettore

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

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

10

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) {

perror("SEMGET\n"); //In caso di errore...

exit(-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) {

perror("Impossibile creare un nuovo processo\n"); //In caso di errore...

exit(-1);

} else if (!pid) { //Codice del figlio Produttore

printf("Sono un Produttore, PID = %d\n", getpid());

for (j=0; j<NUM_PRODUZ; j++) {

k=Richiesta_Produzione_Vector(Ptr_Buf, ID_sem);

Produzione_Vector(k, value, Ptr_Buf);

Rilascio_Produzione_Vector(k, Ptr_Buf, ID_Sem);

value++; //Avanza nell'alfabeto

sleep(5); //Simula un tempo di produzione

}

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) {

perror("Impossibile creare un nuovo processo\n"); //In caso di errore...

exit(-1);

} else if (!pid) { //Codice del figlio Consumatore

printf("Sono un Consumatore, PID = %d\n", getpid());

sleep(3); //Attende prima di tentare di consumare

for (j=0; j<NUM_CONSUM; j++) {

k=Richiesta_Consumo_Vector(Ptr_Buf, ID_Sem);

consumo=Consumo_Vector(k, Ptr_Buf);

Rilascio_Consumo_Vector(k, Ptr_Buf, ID_Sem);

sleep(5); //Simula un tempo di consumo

}

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++) { //Il padre rimane in attesa che i figli terminino...

pid=wait(&status);

printf("Il figlio con PID %d è terminato!\n",pid);

}

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

shmctl(ID_Buf, IPC_RMID, 0);

semctl(ID_Sem, 0, IPC_RMID);

} 11

Problemi di mutua esclusione nel modello a memoria comune

Scrivere una applicazione concorrente che implementi il problema dei

V)

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

processi lettori processi scrittori

assuma che i abbiano la massima priorità e che i possano invece subire

starvation. I vincoli possono essere così riassunti:

• processo scrittore

Il attivo opera ogni volta una “sovrascrittura” del contenuto del buffer.

• processo scrittore processi lettori processi scrittori

Finchè è attivo un i e gli altri devono

attendere (a garanzia della consistenza del contenuto del buffer).

• processi lettori processi scrittori

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

• processo lettore processi lettori

Finchè è attivo almeno un tutti i che sopraggiungono hanno diritto di

processi scrittori

prelazione rispetto ad eventuali 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 { //Definizione del Buffer

char value;

int lettori;

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

B->value=(char)0;

B->lettori=0;

}

void Init_Semafori(int ID_Sem) {

INITIALIZE(MUTEX,1);

INITIALIZE(SYNCH,1);

}

void Inizio_Lettura(Buffer* B, int ID_Sem) {

WAIT(MUTEX);

B->lettori++;

printf("Attualmente %d processi lettori\n", B->lettori);

if (B->lettori==1) {

WAIT(SYNCH);

printf("Il processo con PID %d è il primo lettore\n", getpid());

}

SIGNAL(MUTEX);

}

char Lettura(Buffer* B) {

char value=B->value;

printf("Il processo con PID %d ha letto %c\n", getpid(), value);

return value; 12

}

void Fine_Lettura(Buffer* B, int ID_Sem) {

WAIT(MUTEX);

B->lettori--;

printf("Attualmente %d processi lettori\n", B->lettori);

if (B->lettori==0) {

SIGNAL(SYNCH);

printf("Il processo con PID %d è stato l\'ultimo lettore\n", getpid());

}

SIGNAL(MUTEX);

}

void Inizio_Scrittura(int ID_Sem) { WAIT(SYNCH); }

void Scrittura(char value, Buffer* B) {

B->value=value;

printf("Il processo con PID %d ha scritto %c\n", getpid(), value);

}

void Fine_Scrittura(int ID_Sem) { SIGNAL(SYNCH); }

→ 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() {

pid_t pid; //Variabili locali

int i;

char value='A', lettura;

int status;

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

key_t Key_Buf=IPC_PRIVATE; //Chiave del buffer

int ID_Buf; //Identificatore del buffer

Buffer* Ptr_Buf; //Puntatore al buffer

ID_Buf=shmget(Key_Buf, DIM, IPC_CREAT|0664); //Viene allocato un segmento di memoria atto a contenere

//un Buffer, 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) {

perror("SHMGET\n"); //In caso di errore...

exit(-1);

}

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) {

perror("SHMAT\n"); //In caso di errore...

shmctl(ID_Buf, IPC_RMID, 0); //Rimuove l'ID della Shared Memory indicata, dealloca

//il segmento di memoria corrispondente ed elimina le

//strutture dati ad esso associate

exit(-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) {

perror("SEMGET\n"); //In caso di errore...

exit(-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) {

perror("Impossibile creare un nuovo processo\n"); //In caso di errore...

exit(-1); 13

} else if (!pid) { //Codice del figlio Scrittore

printf("Sono un aspirante Scrittore, PID = %d\n", getpid());

if (i>0) { //Se non è il primo scrittore...

value++;

sleep(5); //Simula la produzione del dato da scrivere

}

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) {

perror("Impossibile creare un nuovo processo\n"); //In caso di errore...

exit(-1);

} else if (!pid) { //Codice del figlio Lettore

printf("Sono un aspirante Lettore, PID = %d\n", getpid());

Inizio_Lettura(Ptr_Buf, ID_Sem);

lettura=Lettura(Ptr_Buf);

Fine_Lettura(Ptr_Buf, ID_Sem);

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

}

} //End For ... NUM_LETT

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

for(i=0; i<NUM_SCRIT+NUM_LETT; i++) { //Il padre rimane in attesa che i figli terminino...

pid=wait(&status);

printf("Il figlio con PID %d è terminato!\n",pid);

}

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

shmctl(ID_Buf, IPC_RMID, 0);

semctl(ID_Sem, 0, IPC_RMID);

} 14

Problemi di mutua esclusione nel modello a memoria comune

Scrivere una applicazione concorrente che implementi il problema dei

VI)

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

processi lettori processi scrittori

assuma che sia i che i abbiano (quando attivi) la massima priorità sui

starvation.

processi dell'altra categoria, sicché ambedue le classi di processi possono subire I vincoli

possono essere così riassunti:

• processo scrittore

Il attivo opera ogni volta una “sovrascrittura” del contenuto del buffer.

• processo scrittore processi lettori processi scrittori

Finchè è attivo un i e gli altri devono

attendere (a garanzia della consistenza del contenuto del buffer).

• processi lettori processi scrittori

Finchè sono attivi uno o più i devono attendere, e finquando è

processo lettore processi lettori

attivo almeno un tutti i che sopraggiungono hanno diritto di

processi scrittori

prelazione rispetto ad eventuali già in attesa.

• processo scrittore processi lettori

Finchè è attivo un i devono attendere, e finquando è attivo almeno

processo scrittore processi scrittori

un tutti i che sopraggiungono hanno diritto di prelazione

processi lettori

rispetto ad eventuali 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 { //Definizione del Buffer

char value;

int lettori;

int scrittori;

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

B->value=(char)0;

B->lettori=0;

B->scrittori=0;

}

void Init_Semafori(int ID_Sem) {

INITIALIZE(MUTEX_LETT,1);

INITIALIZE(MUTEX_SCRIT,1);

INITIALIZE(MUTEX,1);

INITIALIZE(SYNCH,1);

}

void Inizio_Lettura(Buffer* B, int ID_Sem) {

WAIT(MUTEX_LETT);

B->lettori++;

printf("Attualmente %d processi lettori\n", B->lettori);

if (B->lettori==1) { 15

WAIT(SYNCH);

printf("Il processo con PID %d è il primo lettore\n", getpid());

}

SIGNAL(MUTEX_LETT);

}

char Lettura(Buffer* B) {

char value=B->value;

printf("Il processo con PID %d ha letto %c\n", getpid(), value);

return value;

}

void Fine_Lettura(Buffer* B, int ID_Sem) {

WAIT(MUTEX_LETT);

B->lettori--;

printf("Attualmente %d processi lettori\n", B->lettori);

if (B->lettori==0) {

SIGNAL(SYNCH);

printf("Il processo con PID %d è stato l\'ultimo lettore\n", getpid());

}

SIGNAL(MUTEX_LETT);

}

void Inizio_Scrittura(Buffer* B, int ID_Sem) {

WAIT(MUTEX_SCRIT);

B->scrittori++;

printf("Attualmente %d processi scrittori\n", B->scrittori);

if (B->scrittori==1) {

WAIT(SYNCH);

printf("Il processo con PID %d è il primo scrittore\n", getpid());

}

SIGNAL(MUTEX_SCRIT);

WAIT(MUTEX);

}

void Scrittura(char value, Buffer* B) {

B->value=value;

printf("Il processo con PID %d ha scritto %c\n", getpid(), value);

}

void Fine_Scrittura(Buffer* B, int ID_Sem) {

SIGNAL(MUTEX);

WAIT(MUTEX_SCRIT);

B->scrittori--;

printf("Attualmente %d processi scrittori\n", B->scrittori);

if (B->scrittori==0) {

SIGNAL(SYNCH);

printf("Il processo con PID %d è stato l\'ultimo scrittore\n", getpid());

}

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() {

pid_t pid; //Variabili locali

int i;

char value='A', lettura;

int status;

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

key_t Key_Buf=IPC_PRIVATE; //Chiave del buffer

int ID_Buf; //Identificatore del buffer

Buffer* Ptr_Buf; //Puntatore al buffer

ID_Buf=shmget(Key_Buf, DIM, IPC_CREAT|0664); //Viene allocato un segmento di memoria atto a contenere

//un Buffer, 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) {

perror("SHMGET\n"); //In caso di errore...

exit(-1);

} 16

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) {

perror("SHMAT\n"); //In caso di errore...

shmctl(ID_Buf, IPC_RMID, 0); //Rimuove l'ID della Shared Memory indicata, dealloca

//il segmento di memoria corrispondente ed elimina le

//strutture dati ad esso associate

exit(-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) {

perror("SEMGET\n"); //In caso di errore...

exit(-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) {

perror("Impossibile creare un nuovo processo\n"); //In caso di errore...

exit(-1);

} else if (!pid) { //Codice del figlio Scrittore

printf("Sono un aspirante Scrittore, PID = %d\n", getpid());

if (i>0) { //Se non è il primo scrittore...

value++;

sleep(5); //Simula la produzione del dato da scrivere

}

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) {

perror("Impossibile creare un nuovo processo\n"); //In caso di errore...

exit(-1);

} else if (!pid) { //Codice del figlio Lettore

printf("Sono un aspirante Lettore, PID = %d\n", getpid());

Inizio_Lettura(Ptr_Buf, ID_Sem);

lettura=Lettura(Ptr_Buf);

Fine_Lettura(Ptr_Buf, ID_Sem);

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

}

} //End For ... NUM_LETT

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

for(i=0; i<NUM_SCRIT+NUM_LETT; i++) { //Il padre rimane in attesa che i figli terminino...

pid=wait(&status);

printf("Il figlio con PID %d è terminato!\n",pid);

}

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

shmctl(ID_Buf, IPC_RMID, 0);

semctl(ID_Sem, 0, IPC_RMID);

} 17

Problemi di cooperazione nel modello a scambio di messaggi

Scrivere una applicazione concorrente che implementi il problema

VII)

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 { //Definizione del Messaggio

long tipo;

char testo[DIM_MSG];

} Messaggio;

void main() {

pid_t pid; //Variabili locali

int i;

int status;

Messaggio RS,RR,DM; //Messaggi: Ready To Send, Ready to Receive, Data Message

//----- ALLOCAZIONE CODA DI MESSAGGI -----

key_t Key_Msg=IPC_PRIVATE; //Chiave della coda di messaggi

int ID_Msg; //Identificatore della coda di messaggi

ID_Msg=msgget(Key_Msg, IPC_CREAT|0664); //Viene allocata una coda di messaggi, le viene associato

//un ID e viene creata una struttura dati ausiliaria che

//consenta di gestirla, con i seguenti permessi

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

if (ID_Msg==-1) {

perror("MSGGET\n"); //In caso di errore...

exit(-1);

}

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

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

if (pid==-1) {

perror("Impossibile creare un nuovo processo\n"); //In caso di errore...

exit(-1);

} else if (!pid) { //Codice del figlio Produttore

printf("Sono il Produttore, PID = %d\n", getpid());

RS.tipo=Ready_To_Send;

strcpy(RS.testo, “Ready_To_Send”);

msgsnd(ID_Msg, (const void*)&RS, DIM_MSG, 0);

printf("Produttore: Ho inviato il Ready To Send\n");

printf("Produttore: Sono in attesa del Ready To Receive\n");

msgrcv(ID_Msg, (const void*)&RR, DIM_MSG, Ready_To_Receive, 0);

if (!strcmp((const char*)RR.testo, "Ready To Receive")) {

DM.tipo=Data_Message;

strcpy(DM.testo, "Hello!");

msgsnd(ID_Msg, (const void*)&DM, DIM_MSG, 0);

printf("Produttore: Ho inviato il Messaggio\n");

}

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

}

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

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

if (pid==-1) {

perror("Impossibile creare un nuovo processo\n"); //In caso di errore...

exit(-1);

} else if (!pid) { //Codice del figlio Consumatore

printf("Sono il Consumatore, PID = %d, in attesa del Ready To Send\n", getpid());

msgrcv(ID_Msg, (const void*)&RS, DIM_MSG, Ready_To_Send, 0);

if (!strcmp((const char*)RS.testo, "Ready To Send")) {

printf("Consumatore: Ho ricevuto il Ready to Send\n");

RR.tipo=Ready_To_Receive;

strcpy(RR.testo, "Ready To Receive");

msgsnd(ID_Msg, (const void*)&RR, DIM_MSG, 0);

printf("Consumatore: Ho inviato il Ready To Receive e sono in attesa del Messaggio\n");

msgrcv(ID_Msg, (const void*)&DM, DIM_MSG, Data_Message, 0);

printf("Consumatore: Messaggio ricevuto!\n");

}

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

}

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

for(i=0; i<2; i++) { //Il padre rimane in attesa che i figli terminino...

pid=wait(&status);

printf("Il figlio con PID %d è terminato!\n",pid);

}

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

msgctl(ID_Msg, IPC_RMID, 0);

} 19

Problemi di cooperazione nel modello a scambio di messaggi

Scrivere una applicazione concorrente che implementi uno schedulatore di processi

VIII)

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 { //Definizione del Messaggio

long tipo;

unsigned int PID;

} Messaggio;

#define N_PROC 5 //Numero di processi da schedulare

void main() {

pid_t pid; //Variabili locali

int i;

int status, found, priority, myPID;

Messaggio msg;

//----- ALLOCAZIONE CODA DI MESSAGGI -----

key_t Key_Msg=IPC_PRIVATE; //Chiave della coda di messaggi

int ID_Msg; //Identificatore della coda di messaggi

ID_Msg=msgget(Key_Msg, IPC_CREAT|0664); //Viene allocata una coda di messaggi, le viene associato

//un ID e viene creata una struttura dati ausiliaria che

//consenta di gestirla, con i seguenti permessi

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

if (ID_Msg==-1) {

perror("MSGGET\n"); //In caso di errore...

exit(-1);

}

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

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

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

if (pid==-1) {

perror("Impossibile creare un nuovo processo\n"); //In caso di errore...

exit(-1);

} else if (!pid) { //Codice del figlio

myPID=getpid(); //Definisce propri PID e priorità

priority=int(rand()) % 3;

printf("Sono il figlio con PID %d e priorità %d\n", myPID, priority);

sleep(int(rand()) % 5); //Attende un tempo casuale da 1 a 5 secondi

//prima di richiedere che venga schedulato

msg.tipo=priority;

msg.PID=myPID;

msgsnd(ID_Msg, (const void*)&msg, DIM_MSG, 0); //Invia la richiesta di schedulazione

msgrcv(ID_Msg, (const void*)&msg, DIM_MSG, (myPID+Ready_To_Schedule_You), 0);

//Attende che lo scheduler invii un messaggio che

//abbia come TIPO esattamente il suo PID sommato

//alla costante Ready_To_Schedule_You

printf("Processo %d in Esecuzione...\n", myPID); //Simulazione di esecuzione...

sleep(1);

msg.tipo=End_of_Execute;

msgsnd(ID_Msg, (const void*)&msg, DIM_MSG, 0); //Comunica allo scheduler la sua terminazione

exit(0); //Il figlio i-esimo termina correttamente

20

}

} //End For ... N_PROC

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

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

priority=1;

found=0;

while (!found) {

if (msgrcv(ID_Msg, (const void*)&msg, DIM_SG, priority, IPC_NOWAIT)!=-1) found=1;

else priority=(priority+1) % 3;

} //Almeno un processo ha richiesto

//la schedulazione...

printf("Mando in esecuzione il processo con PID %d e priorità %d\n", 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);

} 21


PAGINE

41

PESO

152.10 KB

PUBBLICATO

+1 anno fa


DETTAGLI
Corso di laurea: Corso di laurea in ingegneria informatica
SSD:
A.A.: 2008-2009

I contenuti di questa pagina costituiscono rielaborazioni personali del Publisher Chiakka87 di informazioni apprese con la frequenza delle lezioni di Sistemi operativi e studio autonomo di eventuali libri di riferimento in preparazione dell'esame finale o della tesi. Non devono intendersi come materiale ufficiale dell'università Napoli Federico II - Unina o del prof De Carlini Ugo.

Acquista con carta o conto PayPal

Scarica il file tutte le volte che vuoi

Paga con un conto PayPal per usufruire della garanzia Soddisfatto o rimborsato

Recensioni
Ti è piaciuto questo appunto? Valutalo!

Altri appunti di Sistemi operativi

Sistemi operativi - domande esame
Appunto
Sistemi operativi - Problema dei produttori e dei consumatori
Appunto
Sistemi operativi - Esercitazioni varie Linux
Esercitazione
Sistemi operativi - Implementazione programma in C
Appunto