Minimal example of proper way of forever-running server like QUdpSocket
-
I currently have a server that should be run until the app closes. I have started it with
QtConcurrent::run
where the server has a forever loop parsing messages and then emiting a signal so that parent thread can access the data. This works as expected except for when I try to exit the program I get a crash because the started thread does not want to finish.I have searched around for a solution and found one possible here: https://forum.qt.io/topic/114871/how-to-stop-qfuture-thread saying that it's possible to use a global variable that is checked every time. This, however, seems like a low-level way of stepping around Qt to do something that should be handled by the server like in built-in Qt classes. For example, with
QUdpSocket
I only have to construct the socket and then callconnect
and the socket takes care of itself and ends properly when the app ends.I have looked a bit at the source of
QUdpSocket
but it subclasses an abstract class and depends which makes it hard to understand how it loops in a proper way. So I'm wondering if there is some tutorial as to how to do this the right way? The tutorial would basically be how to create forever-running futures that continually yield results and then close at the end. -
Then don't use QtConurrent::run() but a proper QThread which is more suitable for your purpose. Also I don't see why a QUdServer needs to be in a separate thread at all.
-
Hi and welcome to the forums.
Qt's network classes are asynchronous pr default meaning that unless you want to do really heavy stuff there is no reason to use a thread at all since the app won't be blocked.
But do you mean how to make such an app in general?
Like for your own server type?
Anyway, say your server does need a thread.
then look at here for various ways.https://github.com/DeiVadder/QtThreadExample
Im a fan of the worker way as it allows reuse of the core object in easy manner.
-
@Christian-Ehrlicher
I might have worded it the wrong way but I'm not trying to putQUdpSocket
in a thread, I'm trying to do whatQUdpSocket
is doing and just useconnect
on my own server and have it emit a signal whenever new data is available. If that is in a thread or not doesn't really matter; I just want it to work the same as that one.Do you know of any examples I could look at?
-
@perry_blueberry said in Minimal example of proper way of forever-running server like QUdpSocket:
Do you know of any examples I could look at?
In the documentation are exactly the 5 lines you need for this.
-
@mrjj said in Minimal example of proper way of forever-running server like QUdpSocket:
Hi and welcome to the forums.
Qt's network classes are asynchronous pr default meaning that unless you want to do really heavy stuff there is no reason to use a thread at all since the app won't be blocked.
But do you mean how to make such an app in general?
Like for your own server type?
Anyway, say your server does need a thread.
then look at here for various ways.https://github.com/DeiVadder/QtThreadExample
Im a fan of the worker way as it allows reuse of the core object in easy manner.
The redmarked is exactly what I want. The example linked seems to be for doing some heavy operation. That example seems to pop up a lot but I think doing a server is fundamentally different (maybe not in Qt?). Probably stating the obvious, put a server is IO bound and runs forever whereas a heavy task is CPU bound and runs to completion. I think the best way to create a server is generally through some sort of asynchronous calls like
QUdpSocket
looks to me from the outside looking in.@Christian-Ehrlicher said in Minimal example of proper way of forever-running server like QUdpSocket:
@perry_blueberry said in Minimal example of proper way of forever-running server like QUdpSocket:
Do you know of any examples I could look at?
In the documentation are exactly the 5 lines you need for this.
I am not trying to implement a UDP server. I am trying to implement my own (CAN). Through continually polling for messages I can get new messages with the library I'm using so for that to work it would need to run in some sort of therad. What that documentation shows is what I want the API for my own server to look like.
-
@perry_blueberry said in Minimal example of proper way of forever-running server like QUdpSocket:
I am not trying to implement a UDP server. I am trying to implement my own (CAN). Through continually polling for messages I can get new messages with the library I'm using so for that to work it would need to run in some sort of therad. What that documentation shows is what I want the API for my own server to look like.
So what's wrong with my first comment then? Use a separate QThread and properly close it on exit instead QtConcurrent::run() which is not designed for this usecase.
-
@Christian-Ehrlicher
I have looked at the examples. From the second example I have this//mainwindow.cpp #include "mainwindow.h" #include "ui_mainwindow.h" #include "WorkerThread.h" #include <QDebug> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); WorkerThread *workerThread = new WorkerThread(); connect(workerThread, &WorkerThread::resultReady, this, &MainWindow::handleResult); connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater); workerThread->start(); } MainWindow::~MainWindow() { delete ui; } void MainWindow::handleResult(const QString &s) { qDebug() << "Got results"; }
//WorkerThread.h #ifndef WORKERTHREAD_H #define WORKERTHREAD_H #include <QThread> class WorkerThread : public QThread { Q_OBJECT void run() override { QString result; /* ... here is the expensive or blocking operation ... */ emit resultReady(result); this->exec(); } signals: void resultReady(const QString &s); }; #endif // WORKERTHREAD_H
From this I see Got results one time. The documentation states that using
exec()
insiderun
I should be able to event loop this and get it to run many times but that doesn't work. I guess I'm doing something fundamentally wrong here? Puttingwhile(true)
causes the same issue as before where the program cannot exit without a crash. -
@perry_blueberry said in Minimal example of proper way of forever-running server like QUdpSocket:
From this I see Got results one time. The documentation states that using exec() inside run I should be able to event loop this and get it to run many times but that doesn't work. I guess I'm doing something fundamentally wrong here? Putting while(true) causes the same issue as before where the program cannot exit without a crash.
I don't want to hurt you, but your QThread usage can not work as it is.
You should never sub-class QThread, especially if you want to use it in combination with QObject:- https://doc.qt.io/qt-5/qthread.html#details : "new slots should not be implemented directly into a subclassed QThread."
- https://www.vikingsoftware.com/how-to-use-qthread-properly/
I don't really understand what you want to achieve, so I can only guess.
Correct me if I am wrong.My understanding, is that you want to perform a "heavy computing" outside the main thread.
For this kind of purpose, I would recommend you to useQtConcurrent::run()
=> https://doc.qt.io/qt-5/qtconcurrentrun.html -
@KroMignon
No worries, I am here to learn :)
But I have to say this keeps on getting more confusing. The example I posted above is taken almost exactly line-by-line from the second example in the Qt documentation that you linked. I have only taken the controller part of it and put it in mainwindow. And it says In that example, the thread will exit after the run function has returned. There will not be any event loop running in the thread unless you call exec(). which makes it seem like you can have this kind of server by callingexec
inrun
(putting it inrun
is mentioned somewhere close in the documentation).What I want to achieve is an asynchronous server that emits a signal when something is ready to be read. This is a very common way to implement some kind of server in many languages and frameworks that I've seen. A server doesn't run to conclusion and only gives results intermittently so it has to be allowed to run forever somehow while producing new results when they arrive.
-
To avoid confusion, when I say server I want to mention that I don't mean a web server or UDP server. I simply mean something that is blocking on some sort of connection to listen for some data. When that data comes it should make the data available for the rest of the application and then go to sleep again until there is something new to read.
-
@perry_blueberry I suggest for your requirement implement ion like this is most suited rather than subclassing thread..
connect required slot to socket ready read signal and
In the slot read the data and emit the read data.Implement the above functionality in the class..
Call it as Worker class. And move this class instance to thread using movetoThread()https://doc.qt.io/qt-5/qthread.html
Use the first example in the link which suggests using moveToThread() -
@perry_blueberry said in Minimal example of proper way of forever-running server like QUdpSocket:
When that data comes it should make the data available for the rest of the application and then go to sleep again until there is something new to read.
The Qt documentation is very huge, and some examples are out-dated.
Qt is an asynchronous framework, almost all Qt class handle this for you.
For example:QTcpSocket
/QTcpServer
QUdpSocket
QSerialPort
- etc.
All those classes handle the "blocking logic" in background and triggers signals "when something happens".
For example for QTcpSocket there are connected(), disconnected(), bytesWritten(), readyRead(), etc.So there is no need to use additional thread for this.
Again, depending on what you want to do there are many strategies you can use for doing things outside from main thread:
- for single operations, the simplest way is to use
QtConcurrent::run()
(maybe in combination withQFutureWatcher()
- or using a "worker class", and using moveToThread() to run it in a background thread
-
@nagesh said in Minimal example of proper way of forever-running server like QUdpSocket:
@perry_blueberry I suggest for your requirement implement ion like this is most suited rather than subclassing thread..
connect required slot to socket ready read signal and
In the slot read the data and emit the read data.Implement the above functionality in the class..
Call it as Worker class. And move this class instance to thread using movetoThread()https://doc.qt.io/qt-5/qthread.html
Use the first example in the link which suggests using moveToThread()I think I understand what you are saying; subclassing should be avoided for
QThread
. I will take a look at the links posted in this thread to get a better understanding of the intricacies.@KroMignon said in Minimal example of proper way of forever-running server like QUdpSocket:
@perry_blueberry said in Minimal example of proper way of forever-running server like QUdpSocket:
When that data comes it should make the data available for the rest of the application and then go to sleep again until there is something new to read.
The Qt documentation is very huge, and some examples are out-dated.
Qt is an asynchronous framework, almost all Qt class handle this for you.
For example:QTcpSocket
/QTcpServer
QUdpSocket
QSerialPort
- etc.
All those classes handle the "blocking logic" in background and triggers signals "when something happens".
For example for QTcpSocket there are connected(), disconnected(), bytesWritten(), readyRead(), etc.So there is no need to use additional thread for this.
Again, depending on what you want to do there are many strategies you can use for doing things outside from main thread:
- for single operations, the simplest way is to use
QtConcurrent::run()
(maybe in combination withQFutureWatcher()
- or using a "worker class", and using moveToThread() to run it in a background thread
My case worked better as a
QThread
because it is very similarQTcpSocket
and the other classes you listed. It was actually shutting down properly in the example I posted above. The issue was that I hadn't put any sleep in between the calls toqDebug
so it quickly overtook the CPU. So everything seems to work as expected.To sum up:
My first misunderstanding was that I was trying to useQtConcurrent::run
which is apparently best suited for single operations.QThread
seems to be the right use for a server.
I also misunderstood the meaning ofexec
. I thought it was a "magic" operator that would callrun
recursively (or something like that) when put at the end ofrun
but it seems to have the purpose of starting the event loop which in turn means startingrun
. In the end what this boils down to is that I hadn't read the API properly and thinks work more-or-less as expected when comparing to other frameworks.I haven't read it yet but https://www.toptal.com/qt/qt-multithreading-c-plus-plus seems like a good additional resource on the topic (for other people who might be stumbling onto the same issue).
-
You have it all here: https://wiki.qt.io/WIP-How_to_create_a_simple_chat_application - single thread, multiple threads, server, client, the works. Courtesy of @VRonin. What you need to do to write this properly is very simple and has nothing to do with threads: you need to make your processing asynchronous. After that it can be in a thread, or not, it doesn't truly matter.
-
@kshegunov
That seems like a great resource! I will take a look.