QEventLoop does not end on exit()
-
Hi,
I'm working on a multithread socketserver (stil using Qt5.15.2). For that purpose I subclassed QTcpServer to override
incomingConnection
.
In the thread object I start an eventloop to use sockets events and nearly everything works as expected.
OnlyQEventLoop::exit()
does not work as described.
According to Qt-Manual on calling exit() exec()-function should terminate, but it does not.Here's my code:
void RESTServer::incomingConnection(qintptr socketDescriptor) { RESTClient* rc = new RESTClient(socketDescriptor, auth, services, this); qDebug() << "new client connected ..."; QThreadPool::globalInstance()->start(rc); }
The client-class constructor:
RESTClient::RESTClient(qintptr socketDescriptor, Authenticator& auth, const QMap<QString, AbstractService*>& services, QObject* parent) : QObject(parent) , sock(&eLoop) , auth(auth) , services(services) { sock.setSocketDescriptor(socketDescriptor); connect(&sock, &QAbstractSocket::disconnected, this, &RESTClient::onDisconnect); connect(&sock, &QIODevice::readyRead, this, &RESTClient::read); connect(&sock, &QAbstractSocket::errorOccurred, this, &RESTClient::error); }
the onDisconnect function:
void RESTClient::onDisconnect() { disconnect(&sock, &QAbstractSocket::disconnected, this, &RESTClient::onDisconnect); disconnect(&sock, &QIODevice::readyRead, this, &RESTClient::read); disconnect(&sock, &QAbstractSocket::errorOccurred, this, &RESTClient::error); qDebug() << "client disconnected ..."; eLoop.exit(); }
and finally the run() function:
void RESTClient::run() { qDebug() << "start client in new thread ..."; eLoop.exec(); qDebug() << "\tRESTClient ended ..."; }
... the log output is like this:
new client connected ... start client in new thread ... client disconnected ... ... new client connected ...
As the message
RESTclient ended ...
does not appear, I guess the thread is not terminated, but stil running. I tried to useQThread::exit()
but then application appeared as corrupted and did not respond to any further events.How can I find the culprit that prevents the thread from ending?
-
This post is deleted!
-
- Is RESTClient really derived from QRunnable ?
- I don't think QThreadPool::start() moves
rc
to the new thread so all stuff is done in the main thread (where RESTServer lives in) - this is for sure not what you want.
-
@Christian-Ehrlicher
Thank you for your attention!-
Yes
-
partially correct. All event callbacks run in main-thread. Only run() runs in new thread. So that's crap. Not what I wanted.
How can I do better?
-
-
@django-Reinhard said in QEventLoop does not end on exit():
partially correct. All event callbacks run in main-thread. Only run() runs in new thread. So that's crap. Not what I wanted.
How can I do better?Use a worker-object approach as shown in the QThread documentation.
-
Hi, just a guess but maybe your sock object also does an eLoop.exec()? If they're stacked then the eLoop.exit() at the end of RESTClient::onDisconnect() will not exit until the exec() inside your sock object also exits.
(You can check if you have multiple outstanding exec()s by looking at QThread's loopLevel). -
@Christian-Ehrlicher said in QEventLoop does not end on exit():
Use a worker-object approach
Hm, can I use that approach together with Threadpool?
I already used the worker approach for an ever running thread, which is created at application start and that never ends.
The RESTClient is supposed to happen many times in possibly short time, so a lot of thread will be created and terminated ...
-
If it's a short-running task then there's no need to create a separate thread at all. If it's a longer running task, create a thread for every socket by your own.
-
Hm, I don't know, how long the creation of the response takes.
A status query may be quite fast and a database query may take some time ...by the way: I tried the linked example - and it does not work for me. May be I miss something.
When I debug the code, the controller-constructor runs and right after it the destruktor of the controller runs. The worker has no chance to start.I tried to manually emit the operate signal, but it did not change anything.
-
I made it work by creating the client class in the new thread. Now it works with the event loop and Threadpool.
The only remaining issue is that close on the socket does not include a flush - which means that a write followed by a close does not transfer anything.
But ok, I can still fix that.