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
-
@QtExchange
Hi,
You're doing it wrong, on multiple counts.Firstly, your objects are all in the main thread!
Secondly, you're reimplementingQThread::run()
instead of using a worker object and the thread's own event loop.
Thirdly (a remark), if you want theQTcpSocket
object that you get fromQTcpServer
to live in another thread you have to reimplement QTcpServer::incomingConnection.
Fourthly, you shouldn't be callingstart()
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 thedelete
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.
-
@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 fromQThread
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
-
@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
-
@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