Comunicazione fra threads



  • Salve ragazzi.
    Provo a descrivere la situazione che mi si presenta e il problema ad esso connesso.

    Nella mia applicaizone ho due Threads:

    1. Un TCPThread (un thread di ascolto su di un Socket) che viene creato nella main page (figlio quindi del thread GUI)
    2. Il main Thread (GUI) che fa funzionare tutta l'applicazione...

    L'utente quindi utilizza l'applicazione gestita dal main thread e può interagire con una serie di dialog. Diaciamo che l'utente a questo punto crea il Dialog1 che crea il Dialog2 etc... In questa situazione ho necessità che il Dialog3 riceva dei dati che il thread TCP sta registrando.

    Nella mia infinita ignoranza avrei ustato una CONNECT se il thread TCP e il Dialog3 fossero stati tutti figli del solito dialog, ma così non è... Uno infatti è figlio di Dialog2 e uno di Mainpage(o GUIthread che dir si voglia).

    Avete qualche consiglio da darmi? Ve ne sarei infinitamente grato.



  • Probabilmente devi semplicemente creare una catena di signals o passare un puntatore all'oggetto che emette i segnali dal TCP. Io preferisco la prima soluzione quindi:

    • creerei un signal in Dialog1 che e' identico a quello emesso dal TCP object, da Mainpage connetti il signal nell'oggetto TCP con quello in Dialog1.
    • creerei un signal in Dialog2 che e' identico a quello in Dialog1 e in Dialog1 connetti i due segnali
    • In Dialog2 connetti il segnale in Dialog2 con lo slot in Dialog3


  • @VRonin
    Capito Ronin. Grazie per la risposta ;)



  • Allora dopo un po' di tempo sono tornato ad occuparmi del problema dei thread...
    L'ultima volta avevo capito che il tuo consiglio consisteva in questo:

    Lancio il mio thread in mainwindow

    TCPThread *thread = new TCPThread;
          thread->start();
    

    faccio le mie cose e poi collego mainwindow con dialog1

    Dialog1 *dia1=new Dialog1();
        dia1->setModal(true);
        connect(this, SIGNAL(sendIdThread(const TCPThread &) ), dia1, SLOT( getIdThread(const TCPThread & )));
        emit sendIdThread(*thread);
        dia1->exec();
    

    stessa cosa farò in Dialog2 e Dialog3

    Dialog2 *dia2=new Dialog2();
        dia2->setModal(true);
        connect(this, SIGNAL(sendIdThread(const TCPThread &) ), dia2, SLOT( getIdThread(const TCPThread & )));
    	emit sendIdThread(*thread);
        dia2->exec();
    

    etc..
    Così finalmente odvrei avere il riferimento al thread nel mio dialog 3. Ho capito bene?
    Il problema che incontro è che già durante il primo passaggio di riferimento nello slot getIdThread(const TCPThread & ) prendo questo errore:
    `

    error: use of deleted function 'TCPThread::TCPThread(const TCPThread&)'
             case 7: _t->getIdThread((*reinterpret_cast< const TCPThread(*)>(_a[1]))); break;
    

    Sapresti indicarmi cosa sbaglio? Grazie mille per la disponibilità



  • TCPThread e' un QObject e i QObject non possono essere copiati. usa i puntatori invece delle referenze: const TCPThread& deve diventare TCPThread* (probabilmente il const e' un po' troppo restrittivo, io l'ho tolto ma lo puoi tenere se pensi sia accettabile)

    P.S.
    Di solito QThread non va reimplementato, protesti postare il codice di TCPThread?



  • @VRonin
    intanto grazie per la risposta. Il codice del thread è :

    .H
    #ifndef TCPTHREAD_H
    #define TCPTHREAD_H
    
    #include "utility/speaktts.h"
    
    #include <QDialog>
    #include <QMainWindow>
    #include <QTcpSocket>
    #include <QThread>
    
    namespace Ui {
    class TCPThread;
    }
    
    class TCPThread : public QThread
    {
        Q_OBJECT
    
    public slots:
        void connectToHost();
        void connected();
        void readServer();
        void sendMessage();
        void delay( int millisecondsToWait );
    
    private slots:
        void on_sendMessage_clicked();
        void on_control_clicked();
    
    
    private:
        Ui::TCPThread *ui;
        void run();
        QTcpSocket *socket;
        SpeakTTS *tts;
    };
    
    #endif // TCPTHREAD_H
    
    .C
    #include "tcpthread.h"
    #include "utility/speaktts.h"
    
    #include <QtGui>
    #include <QtNetwork>
    #include <QFormLayout>
    #include <QLineEdit>
    #include <QSpinBox>
    #include <QPushButton>
    #include <QTextEdit>
    #include <QString>
    #include <QTime>
    #include <QThread>
    #include <QtMath>
    #include <QVector>
    
    typedef struct
    {
        long quotaX; //coord x
        long quotaY; //coord y
        long flags;  //touch
        long progressivo;
    }DATI;
    
    void TCPThread::run()
    {
        //Creo il socket TCP
        socket=new QTcpSocket();
    
        connect(socket, SIGNAL(connected()), this, SLOT(connected()));
        connect(socket, SIGNAL(readyRead()), this, SLOT(readServer()));
    
        this->connectToHost();
        bool connected=false;
        //Cicolo infinito di ascolto
        while(1){
            //Se la connessione esiste invio il messaggio
            connected = (socket->state() == QTcpSocket::ConnectedState);
            if(connected){
                //Invio un messaggio di "polling" per ricevere le coordinate dal server
                sendMessage();
                delay(250);
                //La connessione non esiste/è caduta, la ripristino
            }else{
                // qDebug() << "Stauts: abort ";
                socket->abort();
                socket->connectToHost(QHostAddress("192.168.2.115"), 5000);
                delay(2000);
                // qDebug() << "Stauts: connect ";
            }
        }
    }
    
    //Stabilisce la connessione con il server
    void TCPThread::connectToHost(){
        socket->connectToHost(QHostAddress("192.168.2.115"), 5000);
    }
    
    void TCPThread::connected(){
        socket->write(QString("Hello Server").toLatin1());
        socket->waitForBytesWritten();
    }
    
    void TCPThread::sendMessage(){
        //Invio un qualsiasi messaggio per avere la risposta coi dati
        socket->write(QString("a").toLatin1());
        //ui->trace->append("Ho inviato il messaggio");
        socket->waitForBytesWritten();
    }
    
    void TCPThread::readServer(){
    
        if(socket->bytesAvailable() < sizeof(DATI)) return;
        const QByteArray raw = socket->read(sizeof(DATI));
        const DATI* const rawData = reinterpret_cast<const DATI*>(raw.constData());
           qDebug() << "Coord X: " +  QString::number(rawData->quotaX) << "Coord Y: " +  QString::number(rawData->quotaY) << "Touch: " +  QString::number(rawData->flags);
        if(rawData->flags==0){
           qDebug() << "Coord X: " +  QString::number(rawData->quotaX) << "Coord Y: " +  QString::number(rawData->quotaY) << "Touch: " +  QString::number(rawData->flags);
        }
        readServer();
    }
    
    //Evento click pulsante messaggio
    void TCPThread::on_sendMessage_clicked()
    {
        this->sendMessage();
    }
    
    //Evento click pulsante connetti
    void TCPThread::on_control_clicked()
    {
        this->connectToHost();
    }
    
    //Funzione per impostare il delay in millisecondi
    void TCPThread::delay( int millisecondsToWait )
    {
        QTime dieTime = QTime::currentTime().addMSecs( millisecondsToWait );
        while( QTime::currentTime() < dieTime )
        {
            QCoreApplication::processEvents( QEventLoop::AllEvents, 100 );
        }
    }
    

    Che fondamentalmente manda un messaggio di un carattere ad un server che gli risponde sempre con 3 valori.



  • Come temevo... la documentazione di QThread e' sbagliata dai tempi di Qt4, tutti si lamentano ma nessuno mai la cambia, ti consiglia di fare cose sbagliate. La spiegazione di come usarli correttamente la trovi qui: https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/ ma, in pratica, nel 99.9% dei casi QThread non va subclassato. Crea una classe che eredita da QObject che faccia il lavoro e usa moveToThread



  • @VRonin
    ok grazie mille per le dritte. Ora mi studio meglio i threads ;)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.