Visualizzazione dei risultati da 1 a 2 su 2

Discussione: [C/C++] Problema uso libreria pthread e code di messaggi

  1. #1
    Utente di HTML.it
    Registrato dal
    Nov 2015
    Messaggi
    27

    [C/C++] Problema uso libreria pthread e code di messaggi

    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 :
    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++;
    in server.cpp , perché , come si vede dall'esecuzione, è da questo punto in poi che il programma non prosegue più.


    Sapreste aiutarmi ? Grazie mille in anticipo a tutti coloro che proveranno ad aiutarmi
    Ultima modifica di Warioss; 03-12-2017 a 21:59

  2. #2
    Utente di HTML.it
    Registrato dal
    Nov 2015
    Messaggi
    27
    Risolto da solo : non veniva visto dai thread il descrittore delle cose di messaggio. Si può chiudere , grazie.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2017 vBulletin Solutions, Inc. All rights reserved.