Visualizzazione dei risultati da 1 a 8 su 8
  1. #1
    Utente di HTML.it
    Registrato dal
    Sep 2010
    Messaggi
    34

    [c++] std::thread e socket

    Ciao a tutti ho un problema, o meglio vorrei un chiarimento su server con un thread che gestisce le connessioni.
    La mia classe server è fatta così:
    server.h
    codice:
    class Server
    {
    public:
    
        /**
        *\brief Costruttore della classe
        */
        Server ();
        /**
        *\brief Distruttore della classe
        */
        virtual ~Server();
        /**
        *\brief Metodo che fa partire il server
        */
        void Start();
        /**
        *\brief Metodo che ferma il server
        */
        void Stop();
        /**
        *\brief Metodo che imposta il segnale di spegnimento del server e attende il completamento delle operazioni
        */
        void WaitForCompletation();
    
    private:
        /**
        *\brief Metodo che implementa la routine del server e lo pone in ascolto sulla porta specificata nel file di configurazione
        */
        void Run ();
        /**
        *\brief Metodo che viene richiamato nel caso di una nuova connessione sul server principale e gestisce le richieste.
        */
        void serviceRoutine(Socket * sock);
    
    private:
        Centrale * centrale;
    //    unsigned char pacchetto[512];
    //    unsigned char recvBuffer[512];
        Database * db_epro;
        Parametri * param;
        Logger * log;
        Socket serversock;
        thread mainthread;
        thread thread_serventi[10];
        int n_thread;
        bool thread_stop;
    };
    
    #endif // SERVER_H
    server.cpp
    codice:
    Server::Server()
    {
    #if (DEBUGSERVER >=2)
        cout<<"Chiamato costruttore della classe server\n";
    #endif
    
        Server::param = new Parametri(FILEPARAM);
    #if (DEBUGSERVERs >=2)
        cout<<"Chiamato new Parametri\n";
    #endif
        Server::db_epro = new Database(param->getParametro(DATABASE),         //Nome db
                                       param->getParametro(IP_DB),            //IP del db
                                       param->getParametro(PORT_DB),          //Porta del db
                                       param->getParametro(USER_DB),          //Nome utente
                                       param->getParametro(PASSWD_DB));       //Password di accesso
        Server::log = new Logger(param->getParametro(FILELOG),param->getParametro(PATHLOG));
    
        n_thread = 0;
    }
    
    Server::~Server()
    {
        cout<<"Distruttore del server\n";
        delete param;
        delete db_epro;
        delete log;
    }
    
    void Server::WaitForCompletation()
    {
        Server::Stop();
        for (int i = 0; i<n_thread; i++)
        {
            thread_serventi[i].join();
        }
        mainthread.join();
    }
    
    void Server::Stop()
    {
        thread_stop = true;
    }
    
    void Server::Start()
    {
        for(int i = 0 ; i< n_thread; i++)
        {
            thread_serventi[i].join();
        }
        mainthread = std::move(std::thread(&Server::Run,this));
        thread_stop = false;
    }
    
    void Server::Run()
    {
        Socket serversock;
        Socket new_sock;
        stringstream Stream;
    
        if(!serversock.create())
        {
            throw SocketException ("Could not create client socket.");
            return;
        }
        cout<< "Creazione avvenuta con successo\n";
        if(!serversock.bind(atol(param->getParametro(PORTASCOLTO).c_str())))
        {
            throw SocketException ( "Could not bind to port." );
            return;
        }
        cout<< "Binding OK!!!\n";
    
        if ( ! serversock.listen() )
        {
            throw SocketException ( "Could not listen to socket." );
        }
        cout<< "Listening OK!!!\n";
    
        serversock.set_non_blocking(true);
        while(!thread_stop)
        {
            serversock.accept(new_sock);
            if (new_sock.is_valid())
            {
                cout<<"Ricevuta connessione\n";
                thread_serventi[n_thread] = move(thread(&Server::serviceRoutine,this,&new_sock));
                n_thread++;
            }
        }
        cout<<"Fermato thread principale del server\n";
        return;
    
    }
    
    void Server::serviceRoutine(Socket * sock)
    {
        unsigned char recvBuff[512];
        unsigned char pacchettoinv[512];
        Centrale * centrale = NULL;
        int start = 0;
        int len = 0;
        short crc = 0XFFFF;
        long codice = 0;
        stringstream Stream;
        int nelem;
        int n;
    
        string query;
        PGresult * res;
    
        sock->set_non_blocking(false);
    
        while(!thread_stop)
        {
            memset(recvBuff,'\0',512);
            start = 0;
            ///Ricezione del pacchetto
            n = sock->recv(recvBuff);
            cout<<"Ricevuto pacchetto\n";
    
            ///Trovo il byte iniziale in caso il buffer sia sporco
            while((recvBuff[start]!= 0x0A) && (start <n))
            {
                start++;
            }
    
            if (n<=0)
            {
                break;;
            }
            else
            {
                printf("Il valore 0x0A si trova in posizione %d\n", start);
                len = recvBuff[start+1];
    
                crc = (recvBuff[start+len+3]&0xFF)+((recvBuff[start+len+4]&0xFF)<<8);
    
                ///Controllo che il pacchetto sia corretto.
                if ((crc&0xFFFF) == Crc_16(&recvBuff[start],len+3))
                {
                    ///Individuo il tipo di pacchetto e mi comporto di conseguenza
                    switch(recvBuff[start+2])
                    {
                    case 0x01:///Pacchetto iniziale
                    {
                        cout<<"Identificato pacchetto iniziale\n";
                        memset(pacchettoinv,'\0',512);
                        codice = (((recvBuff[start+3]>>4)&0x0F)*100000)+
                                 ((recvBuff[start+3]&0x0F)*10000)      +
                                 (((recvBuff[start+4]>>4)&0x0F)*1000)  +
                                 ((recvBuff[start+4]&0x0F)*100)        +
                                 (((recvBuff[start+5]>>4)&0x0F)*10)    +
                                 ((recvBuff[start+5]&0x0F)*1)          ;
                        Stream<<codice;
                        query = "SELECT ce_modalita_telegestione FROM centrali WHERE ce_id = '";
                        query.append(Stream.str());
                        query.append("';");
                        res = db_epro->eseguiQuery(query,1);
    
                        if ((strcmp(PQgetvalue(res,0,0),"TECNOOUT")==0)||(strcmp(PQgetvalue(res,0,0),"TECNO OUT")==0))
                        {
                            centrale = new xxx(codice);
                            //centrale->Start();
                        }///Qui si introdurranno altre centrali
                        else
                        {
                            cout<<"Centrale non valida\n";
                            n_thread--;
                            return;
                        }
                        pacchettoinv[0] = 0x0A;
                        pacchettoinv[1] = 0x00;
                        pacchettoinv[2] = 0x09;
                        crc = Crc_16(pacchettoinv,3);
                        pacchettoinv[3] = crc & 0xFF;
                        pacchettoinv[4] = (crc >> 8) & 0xFF;
                        sock->send(pacchettoinv,5);
    
                        break;
                    }
                    case 0x03: ///Richiesta stato della centrale
                    {
                        cout<<"Identificato pacchetto richiesta stato centrale\n";
                        memset(pacchettoinv,'\0',512);
                        pacchettoinv[0] = 0x0A;
                        pacchettoinv[1] = 0x01;
                        pacchettoinv[2] = 0x06;
                        pacchettoinv[3] = centrale->getStatoCentrale();
                        crc= Crc_16(pacchettoinv,4);
                        pacchettoinv[4] = crc & 0xFF;
                        pacchettoinv[5] = (crc >> 8) & 0xFF;
    
                        sock->send(pacchettoinv,6);
                        break;
                    }
                    case 0x04: ///Richiesta stato della zona
                    {
                        cout<<"Identificato pacchetto richiesta stato zona\n";
                        memset(pacchettoinv,'\0',512);
                        nelem=(((recvBuff[start+3]>>4)&0x0F)*1000) +
                              ((recvBuff[start+3]&0x0F)*100)       +
                              (((recvBuff[start+4]>>4)&0x0F)*10)   +
                              ((recvBuff[start+4]&0x0F)*1);
                        pacchettoinv[0] = 0x0A;
                        pacchettoinv[1] = 0x01;
                        pacchettoinv[2] = 0x07;
                        pacchettoinv[3] = centrale->getStatoZone(nelem);
                        crc= Crc_16(pacchettoinv,4);
                        pacchettoinv[4] = crc & 0xFF;
                        pacchettoinv[5] = (crc >> 8) & 0xFF;
                        sock->send(pacchettoinv,6);
                        break;
                    }
                    case 0x05: ///Richiesta stato della partizione
                    {
                        cout<<"Identificato pacchetto richiesta stato partizione\n";
                        memset(pacchettoinv,'\0',512);
                        nelem=(((recvBuff[start+3]>>4)&0x0F)*10) +
                              ((recvBuff[start+3]&0x0F)*1)       ;
                        pacchettoinv[0] = 0x0A;
                        pacchettoinv[1] = 0x01;
                        pacchettoinv[2] = 0x08;
                        pacchettoinv[3] = centrale->getStatoPartizioni(nelem);
                        crc= Crc_16(pacchettoinv,4);
                        pacchettoinv[4] = crc & 0xFF;
                        pacchettoinv[5] = (crc >> 8) & 0xFF;
                        sock->send(pacchettoinv,6);
                        break;
                    }
                    }
                }
                else
                {
                    cout<<"Errore nel CRC\n";
                }
            }
        }
        if (centrale != NULL)
        {
            //centrale->WaitForCompletation();
            delete centrale;
            cout<<"Qui ci arrivo\n";
        }
        sock->chiudi();
        n_thread--;
        return;
    }
    ora il mio dubbio è:
    nel metodo Run è giusto creare un array di thread e attivarli mano a mano che ricevo connessioni
    o sarebbe meglio avere un solo thread e farlo detached?
    se si come?
    Attualmente quando chiudo il programma ho un errore e credo sia dovuto al fatto di avere dei thread in sospeso.

  2. #2
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Occorre fare molta attenzione con i thread detached: la loro esecuzione continua anche dopo che la crt invoca i distruttori delle classi, per cui se vuoi thread detached bisogna lavorare con codice C (quasi puro).

    Qui hai due problemi: il primo riguarda il lifetime delle variabili, il secondo è una race condition abbastanza banale.

    1° Problema (con le righe coinvolte) :
    codice:
    Server::Run() {
        Socket new_sock;
        ...
        while(!thread_stop)
        {
            serversock.accept(new_sock);
            if (new_sock.is_valid())
            {
                cout<<"Ricevuta connessione\n";
                thread_serventi[n_thread] = move(thread(&Server::serviceRoutine,this,&new_sock));
                n_thread++;
            }
        }
        ...
    }
    Quando thread_stop == true la funzione esce e tutte le variabili al suo interno distrutte. Questo vale anche per new_sock. Però tu non chiedi ai thread_serventi di fermare la loro esecuzione con la join(). Questi thread continueranno la loro esecuzione anche dopo che sei uscito da Run(), di conseguenza il parametro new_sock che ricevono non è più valido all'interno della funzione service routine. E questo perchè lo passi per indirizzo e non per copia.
    In breve l'errore è qui: &new_sock

    Il secondo problema è che sia thread_stop sia n_thread non sono atomiche e questo può portare a problemi di sincronizzazione tra Run() e Server::WaiForEtc(). Se il tuo compilatore supporta std::atomic<> (header <atomic> rendi atomiche quelle sue variabili.

    Ultima cosa: non è detto che il join() riesca sempre. Se il thread non è joinable o è detached invocare una join() lancia un'eccezione.
    La cosa corretta sarebbe fare:
    codice:
        for (int i = 0; i<n_thread; i++)
        {
            if (thread_serventi[i].joinable()) thread_serventi[i].join();
        }
        if (mainthread.joinable()) mainthread.join();
    This code and information is provided "as is" without warranty of any kind, either expressed
    or implied, including but not limited to the implied warranties of merchantability and/or
    fitness for a particular purpose.

  3. #3
    Utente di HTML.it
    Registrato dal
    Sep 2010
    Messaggi
    34
    Ciao e grazie della tua risposta ora mi è più chiaro. Ogni giorno capisco sempre qualcosa in più.
    Oggi ho fatto delle prove come mi hai detto tu passando new_sock come copia. Il problema è che se lo passo come copia la funzione serviceroutine non funziona e errno sulla socket mi restituisce un "Bad file descriptor" ora credo che questo sia dovuto a come è fatta la classe socket.
    Ti dico che questa l'ho trovata in internet e non l'ho compresa fino in fondo. Quindi ti chiederei se puoi darmi una mano a comprenderla.


    codice:
    // Definition of the Socket class
    
    #ifndef Socket_class
    #define Socket_class
    
    #include <iostream>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netdb.h>
    #include <unistd.h>
    #include <string>
    #include <arpa/inet.h>
    
    
    const int MAXHOSTNAME = 200;
    const int MAXCONNECTIONS = 5;
    const int MAXRECV = 500;
    
    using namespace std;
    
    class Socket
    {
    public:
        Socket();
        virtual ~Socket();
    
        // Server initialization
        /**
        *\brief Imposta il socket e le sue opzioni
        *\return true se l'operazione ha avuto successo
        */
        bool create();
        /**
        *\brief Effettua il binding in caso di server
        *\param [in] port contiene la porta sulla quale effettuare il binding
        *\return true se l'operazione ha avuto successo
        */
        bool bind ( const long port );
        /**
        *\brief Imposta il socket in modalità ascolto.
        *\return true se l'operazione ha avuto successo
        */
        bool listen() const;
        /**
        *\brief permette di accettare connessioni in ingresso sulla porta sulla quale si è in ascolto
        *\param [out] Socket& contiene il nuovo socket per gestire la connessione
        *\return true se l'operazione ha avuto successo
        */
        bool accept ( Socket& ) const;
    
        // Client initialization
        /**
        *\brief Permette di connettersi ad un server
        *\param [in] host contiene l'indirizzo al quale connettersi
        *\param [in] port contiene la porta sulla quale connettersi
        *\return true se l'operazione ha avuto successo
        */
        bool connect ( const std::string host, const long port );
    
        // Data Transimission
        /**
        *\brief permette di inviare informazioni attraverso il socket
        *\param [in] s puntatore all'array di caratteri che contiene l'informazione da inviare
        *\param [in] len contiene la lunghezza dell'array
        *\return true se l'operazione ha avuto successo
        */
        bool send ( unsigned char * s, int len ) const;
        /**
        *\brief Permette la lettura di informazioni dal socket
        *\param [out] s contiene l'informazione letta dal socket
        *\return il numero di byte letti.
        */
        int recv ( unsigned char * s ) const;
    
        /**
        *\brief Metodo che permette di impostare il socket come non bloccante
        *\param [in] Se true imposta il socket come non bloccante
        */
        void set_non_blocking ( const bool );
    
        /**
        *\brief Metodo che serve per identificare se il socket è ancora valido
        *\return true in caso il socket sia ancora valido
        */
        bool is_valid() const
        {
            return m_sock != -1;
        }
    
        void chiudi();
    private:
    
        int m_sock;
        sockaddr_in m_addr;
    
    
    };
    
    
    #endif
    Socket.cpp
    codice:
    // Implementation of the Socket class.
    
    
    #include "Socket.h"
    #include <string.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <iostream>
    
    
    
    Socket::Socket() :
        m_sock ( -1 )
    {
    
        memset ( &m_addr,
                 0,
                 sizeof ( m_addr ) );
    
    }
    
    Socket::~Socket()
    {
        if ( is_valid() )
            ::close ( m_sock );
    }
    
    bool Socket::create()
    {
        m_sock = socket ( AF_INET,
                          SOCK_STREAM,
                          0 );
    
        if ( ! is_valid() )
            return false;
    
    
        // TIME_WAIT - argh
        int on = 1;
        if ( setsockopt ( m_sock, SOL_SOCKET, SO_REUSEADDR, ( const char* ) &on, sizeof ( on ) ) == -1 )
            return false;
    
    
        return true;
    
    }
    
    
    
    bool Socket::bind ( const long port )
    {
    
        if ( ! is_valid() )
        {
            return false;
        }
    
    
    
        m_addr.sin_family = AF_INET;
        m_addr.sin_addr.s_addr = INADDR_ANY;
        m_addr.sin_port = htons ( port );
    
        int bind_return = ::bind ( m_sock,
                                   ( struct sockaddr * ) &m_addr,
                                   sizeof ( m_addr ) );
    
    
        if ( bind_return == -1 )
        {
            return false;
        }
    
        return true;
    }
    
    
    bool Socket::listen() const
    {
        if ( ! is_valid() )
        {
            return false;
        }
    
        int listen_return = ::listen ( m_sock, MAXCONNECTIONS );
    
    
        if ( listen_return == -1 )
        {
            return false;
        }
    
        return true;
    }
    
    
    bool Socket::accept ( Socket& new_socket ) const
    {
        int addr_length = sizeof ( m_addr );
        new_socket.m_sock = ::accept ( m_sock, ( sockaddr * ) &m_addr, ( socklen_t * ) &addr_length );
    
        if ( new_socket.m_sock <= 0 )
            return false;
        else
            return true;
    }
    
    
    bool Socket::send ( unsigned char * s, int len ) const
    {
        int status = ::send ( m_sock, s, len, MSG_NOSIGNAL );
        if ( status == -1 )
        {
            return false;
        }
        else
        {
            return true;
        }
    }
    
    
    int Socket::recv ( unsigned char * s ) const
    {
        unsigned char buf [ MAXRECV + 1 ];
    
        memset ( buf, 0, MAXRECV + 1 );
    
        int status = ::recv ( m_sock, buf, MAXRECV, 0 );
        if(-1 == status)
               {
                 switch(errno)
                   {
                   case EAGAIN :// no messages
                     break;
                   case EBADF :
                     cerr << "Bad file descriptor" << endl;
                     break;
                   case ECONNRESET :
                     cerr << "Connection reset" << endl;
                     break;
                   case EINTR :
                     cerr << "Signal interrupt" << endl;
                     break;
                   case ENOTCONN :
                     cerr << "Not connected" << endl;
                     break;
                   case ENOTSOCK :
                     cerr << "Not a socket" << endl;
                     break;
                   case EOPNOTSUPP :
                     cerr << "Not supported" << endl;
                     break;
                   case ETIMEDOUT :
                     cerr << "Timed out" << endl;
                     break;
                   default :
                     cerr<<"Unknown" <<endl;
                     break;
    			}
    		}
    
        if ( status == -1 )
        {
            std::cout << "status == -1   errno == " << errno << "  in Socket::recv\n";
            return 0;
        }
        else if ( status == 0 )
        {
            return 0;
        }
        else
        {
            memcpy(s,buf,status);
            return status;
        }
    }
    
    
    
    bool Socket::connect ( const std::string host, const long port )
    {
        if ( ! is_valid() ) return false;
    
        m_addr.sin_family = AF_INET;
        m_addr.sin_port = htons ( port );
    
        int status = inet_pton ( AF_INET, host.c_str(), &m_addr.sin_addr );
    
    
        if ( errno == EAFNOSUPPORT ) return false;
    
        status = ::connect ( m_sock, ( sockaddr * ) &m_addr, sizeof ( m_addr ) );
    
        if ( status == 0 )
            return true;
        else
            return false;
    }
    
    void Socket::set_non_blocking ( const bool b )
    {
    
        int opts;
    
        opts = fcntl ( m_sock,
                       F_GETFL );
    
        if ( opts < 0 )
        {
            return;
        }
    
        if ( b )
            opts = ( opts | O_NONBLOCK );
        else
            opts = ( opts & ~O_NONBLOCK );
    
        fcntl ( m_sock,
                F_SETFL,opts );
    
    }
    
    void Socket::chiudi()
    {
        close(m_sock);
    }
    La classe l'ho presa da qui http://tldp.org/LDP/LG/issue74/tougher.html

  4. #4
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Il distruttore di Socket chiude la connessione quando Run() termina, pertanto tutte le connessione associate a quello specifico socket vengono interrotte. Per impedire che il socket interno a Socket sia chiuso è possibile inserire un reference counter, ma dato che usi un compilatore C++11, a mio avviso la soluzione più elegante è usare un move constructor.
    In questo modo i dati interni saranno spostati da un Socket all'altro senza problemi.

    Penrtanto io modificherei la classe così:

    In Socket.h
    codice:
    class Socket {
        Socket();
        // no costruttore di copia
        Socket(const Socket& ) = delete;
        // no operatore di assegnamento
        Socket& operator=(const Socket& ) = delete;
    
        // costruttore di spostamento
        Socket(Socket&& rhs);
        // operatore di spostamento
        Socket& operator=(Socket&& rhs);
    
        ...
    };
    In socket.cpp
    codice:
    // costruttore di spostamento. Sposta i dati da rhs a *this
    Socket::Socket(Socket&& rhs) : m_sock(rhs.m_sock) {
    
       //invalida rhs.m_sock;
       rhs.m_sock=-1;
       // copia da rhs.m_addr a this->m_addr
       memcpy(&m_addr,rhs.m_addr,(sizeof(m_addr));
       // annulla rhs.m_addr
       memset(&m_addr,0,sizeof(m_addr));
    }
    // operatore di spostamento
    Socket& Socket::operator=(Socket&& rhs) {
       if (&rhs != this) {
           m_sock = rhs.m_sock;
           //invalida rhs.m_sock;
           rhs.m_sock=-1;
           // copia da rhs.m_addr a this->m_addr
           memcpy(&m_addr,rhs.m_addr,(sizeof(m_addr));
           // annulla rhs.m_addr
           memset(&m_addr,0,sizeof(m_addr));
       }
       return *this;
    }
    In Server::Run()
    codice:
    // per evidenziare meglio
    thread_serventi[n_thread] = move( 
        thread(
            &Server::serviceRoutine,this,move(new_sock)
        )
    );
    Nuovo prototipo di Server::serviceRoutine()
    codice:
    void Server::serviceRoutine(Socket sock)
    This code and information is provided "as is" without warranty of any kind, either expressed
    or implied, including but not limited to the implied warranties of merchantability and/or
    fitness for a particular purpose.

  5. #5
    Utente di HTML.it
    Registrato dal
    Sep 2010
    Messaggi
    34
    Grazie della tua disponibilità ma ho ancora qualche problema più che altro perché non ho ben capito il tuo codice.
    Ho copiato il tuo codice così come lo hai postato nella classe socket e nel metodo run ma quando compilo compare il seguente errore:
    codice:
    /usr/include/c++/4.6/functional 1287 error: use of deleted function ‘Socket::Socket(const Socket&)’
    e non saprei come risolvere visto che non ho ben capito che cosa hai fatto nella classe Socket

    PS dove hai imparato tutte ste cose? io ho cercato qualche libro ma non ho trovato nulla di specifico a parte un libro da 90 € e su internet non trovo tanti esempi e quelli che trovo sono banali e il più delle volte non adatti al mio caso.

    Grazie

  6. #6
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    A quanto pare l'implementazione di di std::function in G++4.6 è buggata. Avevo letto qualcosa in proposito e probabilmente l'hanno sistemata nella versione 4.7.
    E io davo per scontato che tu usassi la 4.7 (del resto non avevi indicato la versione del compilatore).

    Lo standard C++11 prevede la sintassi funzione() = delete per imporre al compilatore il divieto di usare una funzione; questò è utile per disabilitare il costruttore di copia e l'operatore di assegnamento senza renderli per forza privati.
    Dato il bug su riportato, però, occorre che almeno il costruttore di copia sia implementato.
    Le funzioni con il doppio && permettono di accedere ai parametri di rhs e poterli modificare. In questo modo se una classe è composta da dati a loro volta spostabili il tempo, di spostamento dati è minore del tempo necessario a copiarli.
    In questo specifico caso non è che cambi molto, ma per altri tipi di classi la copia di dati è molto più onerosa rispetto al solo spostarli.

    Per fortuna però il bug su riportato è solo per std::function (all'interno del costruttore di std::thread), pertanto la classe Socket modificata è comunque corretta e potenzialmente usabile tramite move().

    Ad esempio se tu volessi invocare Server::serviceRoutine() senza passare dai thread, rimane valida la sintassi
    codice:
    serviceRoutine(move(new_sock));
    e non valida la sintassi
    codice:
    serviceRoutine(new_sock); // errore no costruttore copia.
    Dato che implementare il costruttore di copia nella classe Socket comporta riscrivere alcune funzioni, io aggiro il problema e ti suggerisco di modificare Run() e ServiceRoutine() così:
    codice:
    void Server::Run()
    {
        Socket serversock;
        std::shared_ptr<Socket> new_sock = std::make_shared<Socket>();
        ...
    
        while(!thread_stop)
        {
            serversock.accept(*new_sock);
            if (new_sock->is_valid())
            {
                cout<<"Ricevuta connessione\n";
                thread_serventi[n_thread] = move(
                    thread(
                        &Server::serviceRoutine,this,move(new_sock)
                    )
                );
                n_thread++;
            }
        }
        cout<<"Fermato thread principale del server\n";
        return;
    
    }
    
    void Server::serviceRoutine(std::shared_ptr<Socket> sock) {
        // nessuna altra variazione
        ...
    }
    In pratica new_sock diventa un puntatore intelligente che mantiene in vita i dati di Socket e si occupa da solo di chiudere la connessione e liberare la memoria.
    In linea teorica andrebbe bene anche un puntatore normale, ma sarebbe solo un complicarsi la vita per niente.

    dove hai imparato tutte ste cose?
    Blog, articoli, varie ed eventuali. In questo periodo stanno uscendo alcuni libri aggiornati al nuovo standard (tra cui quello di Stroustroup), però non ho seguito un percorso lineare.
    Ti posso consigliare alcune voci base (in English of course):

    Una panoramica generale
    http://en.wikipedia.org/wiki/C%2B%2B0x

    Un riferimento aggiornato alle novità:
    http://en.cppreference.com/w/

    La pagina che riporta i progressi dei vari compilatori riguardo lo standard in generale.
    http://wiki.apache.org/stdcxx/C++0xCompilerSupport
    This code and information is provided "as is" without warranty of any kind, either expressed
    or implied, including but not limited to the implied warranties of merchantability and/or
    fitness for a particular purpose.

  7. #7
    Utente di HTML.it
    Registrato dal
    Sep 2010
    Messaggi
    34
    Grazie mille funziona. Ti devo più di qualche birra mi hai risparmiato un sacco di tempo
    Ho preferito aggiornare il compilatore.
    Adesso sistemo un attimo la gestione dei thread che quell'array non è molto funzionale visto che se un thread nato dopo un altro e termina che termina dopo mi incasina la cosa...
    E per fortuna sono Ing. Informatico ... Troppa poca programmazione all'università

  8. #8
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Originariamente inviato da Giane88
    Troppa poca programmazione all'università
    I linguaggi si evolvono più velocemente dei corsi. Il prossimo standard (una revisione almeno) è previsto per il 2014. Una major release per il 2017. Starci dietro con altre 1000 cose da fare non è semplice. Se riesci a dedicare un po' di tempo per studiare i nuovi costrutti, non impiegherai molto a padroneggiarli.
    This code and information is provided "as is" without warranty of any kind, either expressed
    or implied, including but not limited to the implied warranties of merchantability and/or
    fitness for a particular purpose.

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 © 2024 vBulletin Solutions, Inc. All rights reserved.