Strange behaviour of Signal/Slots (QtNetwork) used over QThread



  • Hey everyone I need your help

    When implementing a network extension for my main program a strange error occured: When I set the server into listening state I am able to connect with a client but the server never processes SIGNAL(newConnection()) itself and thus I'm unable to work on.

    Has anybody an idea how to solve it ?

    I'm breaking down the code to the most relevant parts.

    Here the content of the .h

    #include <QtNetwork>
    #include <QTcpServer>
    #include <QTcpSocket>
    
    class NetworkEvents: public QThread
    {
    	Q_OBJECT:
    public:
    	QEventLoop *networkLoop;
    	NetworkEvents(QObject *mainObj, QTcpServer* theServer);
    protected:
    	void run();
    private:
    	QTcpServer* server;
    
    public slots:
    	void incommingCnt();
    };
    
    class NetworkSupport: public QObject
    {
    	Q_OBJECT
    public:
    	NetworkSupport(QObject* mainObj);
    private:
    	NetworkEvents* events;
    protected:
    	QTcpServer* server;
    };
    

    Here the content of the .cpp

    NetworkEvents::NetworkEvents(QObject* mainObj, QTcpServer * theServer)
    {
    	networkLoop = new QEventLoop(mainObj);
    	server = theServer;
    	start();
    }
    
    void NetworkEvents::incommingCnt()
    {
    	printf("successfully connected\n");
    }
    
    void NetworkEvents::run()
    {
    	if(server->isListening())
    	{
    			connect(server, SIGNAL(newConnection()), this, SLOT(incommingCnt()));
    			printf("running eventloop\n");
    			networkLoop->exec();
    	}
    }
    
    NetworkSupport::NetworkSupport(QObject *mainObj):QObject(mainObj)
    {
    	server = new QTcpServer(mainObj);
    	server->listen(QHostAdress::Any, 5200);
    	events = new NetworkEvents(mainObj, server);
    	printf("successfully initiated W-LAN communication\n");
    }
    

    NetworkSupport(mainObj) again gets called by the main program. I need to implement the QEventLoop in an extra thread due to interferrences with the main application.

    NB: all the printf()s are executed but the one in incommingCnt()

    Kind Regards


  • Qt Champions 2016

    @QtExchange
    Hi,
    You're doing it wrong, on multiple counts.

    Firstly, your objects are all in the main thread!
    Secondly, you're reimplementing QThread::run() instead of using a worker object and the thread's own event loop.
    Thirdly (a remark), if you want the QTcpSocket object that you get from QTcpServer to live in another thread you have to reimplement QTcpServer::incomingConnection.
    Fourthly, you shouldn't be calling start() in the constructor.
    And finally, you have a race condition:

    void NetworkEvents::run()
    {
        if(server->isListening()) // << Calling a method of an object in one thread
        // ...
    }
    
    NetworkSupport::NetworkSupport(QObject *mainObj):QObject(mainObj)
    {
        server = new QTcpServer(mainObj);
        server->listen(QHostAdress::Any, 5200);  // << Calling, initializing and using an object in another thread
        // ...
    }
    

    Fix all of those, and everything should start to work smoothly.
    Kind regards.

    PS.

    networkLoop = new QEventLoop(mainObj);
    

    This is not freed anywhere, so if you didn't cut the delete only for the example code, then you have a memory leak as well.
    I need sleep, you parented it, so it's just fine.

    PS 2.
    Are you sure there is indeed a pending connection to that port?



  • @kshegunov thank you very much, I'm already taking out some mistakes. My client program reacts on SIGNAL(connected()), which was only emitted when the server as shown above was running.


  • Qt Champions 2016

    @QtExchange
    I suggest first testing with a single threaded code. Then, when you're sure it's working fine and all the connections are okay, you can make the worker object and start a new thread, move the worker to that thread and connect the signals. When that's fixed (this means not deriving from QThread and not using a local event loop) you should start to see the slots called responding to the signals emitted from the tcp socket objects.



  • @kshegunov it was already working in a laboratory situation, these errors only occur since the integration in the main program.

    What exactly do you mean by do not reimplement ::run() (what is the alternative?), if I transfer the code from the run() (as shown above) directly to the constructor (including the exec()) everything runs fine already but then the main program gets stuck on this infinit-exec()-loop too. This is the reason why I implemented the thread/run, but when this is executed in the run() it starts ignoring its signals


  • Qt Champions 2016

    @QtExchange
    Here is some reading material on how to use threads with event loop (which should be in 99.99% of cases), start from top to bottom the first one being the simplest and most relevant:

    https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
    http://forum.qt.io/topic/64346/qtextdocument-and-multithreading/2
    http://forum.qt.io/topic/63482/qthreads-and-constantly-reusing-the-same-thread-objects/2



  • @kshegunov ah should have read longer...

    if I got you right I'm just doing the implementation and the threading in the wrong order, let me check on that


  • Qt Champions 2016

    @QtExchange
    Forgot to link those two, which are very important to understand before working with threads:
    QObjects' thread affinity: http://doc.qt.io/qt-5/qobject.html#thread-affinity
    Queued connections accros threads: http://doc.qt.io/qt-5/threads-qobject.html#signals-and-slots-across-threads



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