Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QTCP threading ... again



  • Hey there,

    Im new in QT and building my first application, which is running on a raspberry and communicating with another application (not QT) using a QtcpServer and "socket-communication". With growing functionality of the application, I ran into perfomance problems (latency of tcp-response) and so I tried to split the applications work into threads - I want to put all tcp communication into a separate thread and reach "independent" processing of the incoming tcp data. Now receiving is working, but I cant send any data, when trying to write to the socket I got "Parent is QNativeSocketEngine(0xaab04210), parent's thread is tch_class(0xbeb26710), current thread is QThread(0x5cb5c0)" I really was searching for an answer but I did not find one (or I did not understand the answers correctly)

    (part of code:)

    class tch : public QThread
    
    void tch::run()
    {
        tcp_socket_init();
        start_socket_listening();
    
        exec();
    
        qtcp_server->close();
    }
    
    void tch::tcp_socket_init()
    {
        qtcp_server = new QTcpServer();
        QObject::connect(qtcp_server, SIGNAL(newConnection()),this, SLOT(tcp_socket_incoming_connection()));
    }
    
    int32_t tch::start_socket_listening()
    {
        if (!qtcp_server->listen(QHostAddress::Any, settings.qtcp_server_port))
        {
            debug_message("failed to start listening");
        }
    	
        return(0);
    }
    
    void tch::tcp_socket_incoming_connection()
    {
        qRegisterMetaType<QAbstractSocket::SocketState>();
        QTcpSocket *tcp_client_socket = qtcp_server->nextPendingConnection();
        connected_tcp_sockets_list.append(tcp_client_socket);
        QObject::connect(tcp_client_socket, SIGNAL(readyRead()), this, SLOT(tcp_read_ready()));
        QObject::connect(tcp_client_socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(tcp_on_changed_socket_state(QAbstractSocket::SocketState)));
    }
    void tch::tcp_read_ready()
    {
        QTcpSocket* tcp_sender = static_cast<QTcpSocket*>(QObject::sender());
        tcp_data.append(tcp_sender->readAll());
    
        tcp_sender->write("world");
    }
    

    This is the class for the tcp handling which is started in the main.
    When executing tcp_sender->write("world") the error is thrown, reading is working... Could someone please explain why? Where do I mix different threads here?
    I would like to have one signal that is emitted when something was received (signal with data and sender to adress the answer later) and one slot that receives a signal (sender for addressing & data) to transmit the answer.

    I read many times that this whole approach (reimplementing run...) is not that good - So...how bad is it? Is there a better way to achive this functionality?

    Please be gentle with a beginner (and his english...) ! Thanks!


  • Lifetime Qt Champion

    As always - your tch is running in the main thread and therefore also the slots as explained in the documentation:

    "It is important to remember that a QThread instance lives in the old thread that instantiated it, not in the new thread that calls run(). This means that all of QThread's queued slots and invoked methods will execute in the old thread. Thus, a developer who wishes to invoke slots in the new thread must use the worker-object approach; new slots should not be implemented directly into a subclassed QThread."


  • Lifetime Qt Champion

    As always - your tch is running in the main thread and therefore also the slots as explained in the documentation:

    "It is important to remember that a QThread instance lives in the old thread that instantiated it, not in the new thread that calls run(). This means that all of QThread's queued slots and invoked methods will execute in the old thread. Thus, a developer who wishes to invoke slots in the new thread must use the worker-object approach; new slots should not be implemented directly into a subclassed QThread."



  • Ok, but why can I read the socket in my case, but writing is throwing this error?
    Now I built another class, like in the example, the controller. And in my case the worker is the tch then, is that correct? And because I used the moveToThread now all slots and signals in tch are living in the new created thread from the controller, are they? The "tcp_sender->write" now seems to work, no error is thrown and the received data is sent back.


  • Lifetime Qt Champion

    @QMICS said in QTCP threading ... again:

    but why can I read the socket in my case, but writing is throwing this error?

    Because only writing modifies the socket directly, reading comes from a buffer so no direct socket access in this case.



  • Thank you Christian, it is working now. Now I included a slot for writing to the socket. When I use moveToThread, QT builds a QueuedConnection around the slots automatically, so I don't have to handle thread safety when using signal-slot - Did I understand that correctly? And because of the buffer and indirect access when reading a socket, the write / read gives no conflict?


  • Lifetime Qt Champion

    @QMICS said in QTCP threading ... again:

    Did I understand that correctly?

    Yes, when you use AutoConnection Qt will determine if Direct or Queued is needed depending on whether source and destination live in the same thread or not.

    And because of the buffer and indirect access when reading a socket, the write / read gives no conflict?

    There is no conflict because now both operations are done in the same thread.



  • @Christian-Ehrlicher said in QTCP threading ... again:

    There is no conflict because now both operations are done in the same thread.

    Oh sure, of course...

    Thank you very much for your help!


Log in to reply