Salve, vi scrivo perché dovrei svolgere il seguente esercizio : https://www.sendspace.com/file/mntjeb (pdf con la traccia) sfruttando code di messaggi, phtread.h,fork ed exec ... insomma tutto quello che forniscono le librerie UNIX in merito a problemi di sincronizzazione tra processi e tra threads.
Ho realizzato il progetto che consta di 4 file (5 contando il Makefile) : client-server.h , client.cpp , server.cpp , master.cpp
Come comprensibile dalla traccia master lancia 3 client ed 1 server e quest'ultimo lancia 3 threads ( 1 Manager e 2 Workers).
I file da me creati sono:
client-server.h:
codice://definisco i parametri della ftok per generare le due code di messaggio univocamente #define REQUEST_QUEUE_PATH "." #define REQUEST_QUEUE_CHAR 'a' #define ANSWER_QUEUE_PATH "." #define ANSWER_QUEUE_CHAR 'b' //definisco gli id delle code di msg e i threads come variabili globali per le starting routines controlla ed elabora static int request_id; static int answer_id; static pthread_t threads[3]; //definisco la struttura "form" che devono compilare i processi client che si collegano al processo server per ottenere l'elaborazione typedef struct { long pid; //è il tipo int n1; int n2; int risposta; } Form; //definisco il buffer condiviso tra threads del proc server come array di record (tabella) typedef struct{ Form f[2]; //in realtà basterebbe 3 perché i 3 client fanno recieve bloccanti prima di fare nuove send int spazio_disp; int mess_disp; int dim; //dimensione totale del buffer, mi serve per l'incremento circolare di testa e coda int testa; int coda; pthread_cond_t MESS_DISP; pthread_cond_t SPAZIO_DISP; pthread_mutex_t mutex; }Buffer; //definisco le funzioni client void compila_form(Form,int,int); //funzione invocata dai processi Client per compilare la struct form void consuma(Form*,int); //funzione invocata dai processi Client per consumare il risultato dell'elaborazione //definisco le funzioni server void* controlla(void*); //funzione invocata dal Thread Manager del Processo Server void* elabora(void*); //funzione invocata dai 2 Threads Worker del Processo Server void init_buffer(Buffer*); //inizalizza il buffer void remove_buffer(Buffer*); //rimuove il buffer
client.cpp:
codice:#include <iostream> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/ipc.h> #include <sys/msg.h> #include <sys/time.h> #include "client-server.h" using namespace std; //definisco le funzioni client void compila_form(Form f,int request_id, int answer_id){//funzione invocata dai processi Client per compilare la struct form srand(time(NULL)); f.pid = getpid(); f.n1 = rand()%11; f.n2 = rand()%11; cout<<"[CLIENT]: valori compilati: "<<f.pid<<" "<<f.n1<<" "<<f.n2<<endl; msgsnd(request_id,&f,sizeof(Form)-sizeof(long),0); cout<<"xd1\n"; consuma(&f,answer_id); } void consuma(Form* f, int answer_id){ //funzione invocata dai processi Client per consumare il risultato dell'elaborazione msgrcv(answer_id,f,sizeof(Form)-sizeof(long),getpid(),0); //recieve bloccante (così non può fare altre send) sul tipo getpid(); cout<<"[CLIENT]:Il valore Consumato dal client di pid "<<getpid()<<" è: "<<f->risposta<<endl; } int main(){ //PARTE DICHIARATIVA key_t request_key , answer_key; int request_id, answer_id; Form f; //PARTE ESECUTIVA //genero le chiavi per le due code di messaggio request_key = ftok(REQUEST_QUEUE_PATH,REQUEST_QUEUE_CHAR); answer_key = ftok(ANSWER_QUEUE_PATH,ANSWER_QUEUE_CHAR); //istanzio le due code di messaggio request_id = msgget(request_key,IPC_CREAT|0664); answer_id = msgget(answer_key,IPC_CREAT|0664); //Esecuzione del cliente ripetuta 5 volte come indicato dalla traccia for(int i = 0; i<5 ; i++) { compila_form(f,request_id,answer_id); } return 0; }
server.cpp :
codice:#include <iostream> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/ipc.h> #include <sys/msg.h> #include <sys/time.h> #include <errno.h> #include <pthread.h> #include "client-server.h" using namespace std; //definisco le funzioni server void* controlla(void* buff){ //funzione invocata dal Thread Manager del Processo Server (Produttore dalla testa) Buffer* b = (Buffer*)buff; Form form; msgrcv(request_id,&form,sizeof(Form)-sizeof(long),0,IPC_NOWAIT);//se va a buon fine ritorna il numero di byte della risposta >0 //è 0 perchè prende il primo mess che trova ed è IPC_NOWAIT //perché non è una reicieve bloccante if(form.n1 == -1 && form.n2 == -1) { //messaggio speciale di uccisione dei workers e disallocazione cout<<"[MANAGER]:Ricevuto Messaggio Speciale\n"; cout<<"[MANAGER]:Terminazione dei Workes\n"; for(int i=0;i<2;i++){ pthread_cancel(threads[i]); } cout<<"[MANAGER]:Disalloco il buffer e le strutture allocate\n"; remove_buffer(b); free(b); msgctl(answer_id,IPC_RMID,0); msgctl(request_id,IPC_RMID,0); exit(0); } else{ //messaggio normale da mandare nel buffer per poi farlo elaborare dai workers pthread_mutex_lock(&b->mutex); while( b->spazio_disp == 0) pthread_cond_wait(&b->SPAZIO_DISP,&b->mutex); cout<<"[MANAGER]:Copia nel buffer di un msg ricevuto da un client\n"; b->f[b->testa]=form; //copio il form nella testa dell'array di form b->testa= (b->testa+1)%(b->dim); //incremento circolare della testa b->spazio_disp--; b->mess_disp++; pthread_cond_signal(&b->MESS_DISP); pthread_mutex_unlock(&b->mutex); } sleep(1); } void init_buffer(Buffer* b){ b->spazio_disp = 2; b->mess_disp = 0; b->testa = 0; b->coda = 0; b->dim=2; pthread_cond_init(&(b->MESS_DISP),NULL); pthread_cond_init(&(b->SPAZIO_DISP),NULL); pthread_mutex_init(&(b->mutex),NULL); printf("[SERVER] - Buffer inizializzato...\n"); } void remove_buffer(Buffer* b){ pthread_cond_destroy(&(b->MESS_DISP)); pthread_cond_destroy(&(b->SPAZIO_DISP)); pthread_mutex_destroy(&(b->mutex)); printf("[SERVER] - Buffer distrutto...\n"); } void* elabora(void* buff){ //funzione invocata dai 2 Threads Worker del Processo Server (Consumatore dalla coda ) Buffer* b = (Buffer*)buff; Form* form; pthread_mutex_lock(&b->mutex); while( b->mess_disp == 0) pthread_cond_wait(&b->MESS_DISP,&b->mutex); *form = b->f[b->coda]; //carico in form l'istanza di coda del buffer form->risposta = form->n1 * form->n2; cout<<"[WORKER]: Valore elaborato :"<<form->risposta<<endl; msgsnd(answer_id,&form,sizeof(Form)-sizeof(long),IPC_NOWAIT); //il tipo di messaggio è già specificato grazie alla getpid() fatta dal client b->coda= (b->coda+1)%(b->dim); //incremento circolare della coda b->spazio_disp++; b->mess_disp--; pthread_cond_signal(&b->SPAZIO_DISP); pthread_mutex_unlock(&b->mutex); } int main(){ //PARTE DICHIARATIVA key_t request_key , answer_key; int request_id, answer_id; pthread_attr_t attr; Form* f; Buffer* b = (Buffer*)malloc(sizeof(Buffer)); //PARTE ESECUTIVA //genero le chiavi per le due code di messaggio request_key = ftok(REQUEST_QUEUE_PATH,REQUEST_QUEUE_CHAR); answer_key = ftok(ANSWER_QUEUE_PATH,ANSWER_QUEUE_CHAR); //istanzio le due code di messaggio request_id = msgget(request_key,IPC_CREAT|0664); answer_id = msgget(answer_key,IPC_CREAT|0664); //setto l'attr come DETACHED,il contrario di joinable ,ossia non è possibile rilevare la teminazione dei thread (che avviene con la cancel) pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); //inizializzo il buffer init_buffer(b); //creo i due threads workers for(int i=0;i<2;i++){ cout<<"[SERVER]:Istanziamento Workers\n"; pthread_create(&threads[i],&attr,elabora,(void*)b); } //creo il thread Manager cout<<"[SERVER]:Istanziamento Manager\n"; pthread_create(&threads[2],&attr,controlla,(void*)b); //non rilevo la fine dei thread in quanto gestita tramite un mess speciale dal thread Manager, termina il Manager e disalloco il resto cout<<"[SERVER]: Terminazione thread Manager\n"; pthread_attr_destroy(&attr); pthread_exit(NULL); //fine del server return 0; }
master.cpp:
codice:#include <iostream> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/ipc.h> #include <sys/msg.h> #include <sys/time.h> #include "client-server.h" using namespace std; int main(){ //PARTE DICHIARATIVA pid_t pid; key_t request_key , answer_key; int request_id, answer_id; int stato; int num_client,num_server,num_proc; //PARTE ESECUTIVA //inizializzo num_client,numserver e numero di processi num_client = 3; num_server = 1; num_proc = num_client+num_server; //genero le chiavi per le due code di messaggio request_key = ftok(REQUEST_QUEUE_PATH,REQUEST_QUEUE_CHAR); answer_key = ftok(ANSWER_QUEUE_PATH,ANSWER_QUEUE_CHAR); //istanzio le due code di messaggio request_id = msgget(request_key,IPC_CREAT|0664); answer_id = msgget(answer_key,IPC_CREAT|0664); //Genero client e server come processi figli con fork ed exec for(int i=0;i<num_proc;i++){ pid=fork(); if(pid==0){ if(i == num_client+num_server-1){ //processo server cout<<"[MASTER]:Istanzio il Server con pid "<<getpid()<<endl; execl("./server","./server",NULL); exit(0); } else{ //processi client cout<<"[MASTER]:Istanzio il Client con pid "<<getpid()<<endl; execl("./client","./client",NULL); exit(0); } } } //rilevo la terminazione dei client for(int i=0;i<num_client;i++){ pid=wait(&stato); if(pid==-1) cout<<"[MASTER]:Errore terminazione client\n"; else cout<<"[MASTER]:Terminato con successo il Client con pid "<<pid<<endl; } //genero ed invio il form speciale per la terminazione del server da inviare al manager Form terminazione; terminazione.pid = getpid(); terminazione.n1 = -1; terminazione.n2 = -1; msgsnd(request_id,&terminazione,sizeof(Form)-sizeof(long),0); //attendo la temrinazione del processo server pid=wait(&stato); cout<<"[MASTER]:Terminato con successo il Server con pid "<<pid<<endl; //Fine cout<<"[MASTER]:Fine\n"; return 0; }
Makefile:
codice:all: master client server main: master.cpp g++ -o master master.cpp client: client.cpp g++ -o client client.cpp server: server.cpp g++ -o server server.cpp -pthread clean: rm -f master client server rm -f *.o
La compilazione avviene senza alcun errore o warning.
Ma l'esecuzione si blocca a questo punto qui :https://ibb.co/hZ5xSw
Ho individuato già le righe critiche :
in server.cpp , perché , come si vede dall'esecuzione, è da questo punto in poi che il programma non prosegue più.codice:b->f[b->testa]=form; //copio il form nella testa dell'array di form b->testa= (b->testa+1)%(b->dim); //incremento circolare della testa b->spazio_disp--; b->mess_disp++;
Sapreste aiutarmi ? Grazie mille in anticipo a tutti coloro che proveranno ad aiutarmi![]()

Rispondi quotando