Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
vuoi
o PayPal
tutte le volte che vuoi
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 -----
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);
}
19Problemi di cooperazione nel modello a scambio di messaggi
Scrivere una applicazione concorrente che implementi uno schedulatore di processiVIII)che gestisce tre livelli di priorità usando le code di messaggi.
Descrizione: Il programma seguente mostra come è possibile implementare uno schedulatore di processi usando lecode di messaggi. Un processo utente che voglia essere schedulato deve inviare allo schedulatore un
Il tuo compito è formattare il testo fornito utilizzando tag html.
ATTENZIONE: non modificare il testo in altro modo, NON aggiungere commenti, NON utilizzare tag h1;
messaggiodi tipo Ready_To_Be_Scheduled, indicando in esso la propria priorità e il proprio PID, dopodiché si pone inattesa, 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à alloscheduler 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 lerichieste disponibili sulla base della priorità dichiarata dai singoli processi e scegliendo il prossimoprocesso 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);}
Problemi di cooperazione nel modello a scambio di messaggi
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.