How do I execute QTcpSocket functions in a different thread?
It's important to note what you can and can't do in terms of threading QTcpSocket:
you can use it in a non-main thread, but only the thread in which it was created in.
you cannot call different functions on the QTcpSocket from different threads, e.g. read in one thread, write in the other. Instead, you can make a seperate thread for each QTcpSocket, which keeps them from using up time and resources that could be painting your widgets in the main thread.
IMO, putting your IO, including QTcpSocket in a thread other than the main thread is a best practice and must-do for any performant application. I use QTcpSocket in non-main threads all the time using the following idiom:
// Read data from a QTcpSocket in a thread. Assumes this is in some class.
m_thread = std::thread([this]
{
QEventLoop eventLoop;
QTcpSocket* socket = new QTcpSocket(&eventLoop);
socket->connectToHost("localhost", 9999);
// enqueue or process the data
QObject::connect(socket, &QTcpSocket::readyRead, &eventLoop, [socket]
{
m_concurrentQueue.push_back(socket->readAll());
});
// Quit the loop (and thread) if the socket it disconnected. You could also try
// reconnecting
QObject::connect(socket, &QTcpSocket::disconnected, &eventLoop, [&eventLoop]
{
eventLoop.quit();
});
eventLoop.exec();
delete socket;
});
where m_thread is some member thread (basically just ensuring that it has a lifetime greater than the current immediate scope), and m_concurrentQueue is some thread-safe queue, or std container with mutex protection.
You'll also want to connect some signal (I usually call it joinAll) to the event loop quit function, and call it from the class destructor. When using an event-loop-in-a-thread idiom you always have to be careful about making sure you can actually destroy the class correctly, otherwise your program won't exit (or on windows it will be terminated, usually with some destructors not getting called, and it ends up being a silent error).
I also usually use a condition variable to wait after creating the thread until the event loop has started. It's not necessary but if you are putting these threads together in constructors it can help make the program flow make more sense.
The QT docs are explicit that the QTCPSocket should not be used accross threads. I.E, create a QTCPSocket in the main thread and have the signal tied to an object in another thread.
I suspect that you are implementing something like a web server where the listen creates a QTCPSocket on the accept. You then want another thread to handle the task of processing that socket. You can't.
The way I worked around it is I kept the socket in the thread it was born in. I serviced all of the incoming data in that thread and threw it into a queue where another thread could work on that data.
virtual void incomingConnection(qintptr socketDescriptor)
Note: If another socket is created in the reimplementation of this method, it needs to be added to the Pending Connections mechanism by calling addPendingConnection().
Note: If you want to handle an incoming connection as a new QTcpSocket object in another thread you have to pass the socketDescriptor to the other thread and create the QTcpSocket object there and use its setSocketDescriptor() method.
What I read in the docs is that QTcpSocket should not be used across threads. If you want to use it in another thread Qt docs say you should create a new QTcpSocket instance in your thread and set the descriptor on the new instance. To do this you need to reimplement QTcpServer and use QTcpServer::incomingConnection. A simple example is provided here.
Put a QMutex lock around all calls, not just on the "different" thread but on all threads. One easy way to do so is via a QMutexLocker
QTcpSocket and QUdpSocket cannot be moved to a different thread once they have been "opened". This is not supported by Qt and (mostly) doesn't work.
While they can be moved when they are in the "closed" state, that's not generally particularly useful.
What you should do is either:
Create the socket inside the thread it will be used in and use signals to marshal the data to be sent/received between threads.
Pass a socketDescriptor from the thread that starts opening the connection across to the thread where the socket should live, and open the socket there using the socketDescriptor.
Common gotchas:
When using QTcpServer, it will open QTcpSockets in the same thread as itself. As they're already open, they cannot be moved.
If you want QTcpServer to open incoming sockets in a different worker thread to the server itself (very common!), you must subclass it and override QTcpServer::incomingConnection() to get access to the socket descriptor before it creates a QTcpSocket. You cannot use the default implementation.
If you are subclassing QThread, do not create the sockets in the constructor. They must be created in QThread::run()
Related
I am creating an application, that communicates with a server using an API's functions, from an existing code base written in C++/Qt 5.6 and Boost. The code is written in a way such that, any communication with the server is done by the API's functions that runs in a worker object. The worker object runs in a QThread(), and is moved using moveToThread.
My problem is that, I need to be able to stop the thread immediately and disconnect in the situation where the network connection drops. However, the thread blocks when it sends data to the server. If I try to stop the thread through quit() or wait(), the request still goes through to the server which is undesirable. The API doesn't offer any method to cancel any ongoing requests either.
My current solution is terminating the thread, and destroying the worker object it owns when the network connection drops. I then create a new QThread and new worker object when connecting to the server.
I know that terminate() or any kind of immediate termination of a thread should be avoided like the plague but it seems to work I think.
The worker object that runs in the QThread uses std::shared_ptr for it's members through std::make_shared.
Are there still chances of memory leaks/corruption?
Apart from this, because I create my QThread in a method, I receive a warning from QT:
QObject: cannot create children for a parent that is in a different thread
Despite this warning, my code still runs but I have doubts. Is it safe to ignore this warning? What are the risks/consequences of ignoring this?
Is it safer to litter the server connecting code with QT's interruption checking points/rewrite it in boost using boost::interruption_point instead of calling terminate? i.e
sendData();
if (QThread::currentThread()->isInterruptionRequested())
{
return;
}
sendData();
if (QThread::currentThread()->isInterruptionRequested())
{
return;
}
...
Advice much appreciated thanks.
a few months ago,i had asked some relative questions about qt tcp network programming for my project. And finally the software came out. But after learned more detail about qt event mechans and signals -slots realization. I have some worry about my program performance and stability.
The key problem is that server using a single thread for handle multiple tcpsockets. the brief introduction code for realization:
incomingConnection function is writen as following: two QSignalMapper are used for map each socket SlotReadyRead and SlotDisconnected
void ServerModule::incomingConnection(qintptr socketDescriptor)
{
m_tcpSocket = new QTcpSocket(this);
if (!m_tcpSocket->setSocketDescriptor(socketDescriptor)) {
return;
}
connect(m_tcpSocket, SIGNAL(readyRead()), m_readyReadSignalMapper, SLOT(map()));
m_readyReadSignalMapper->setMapping(m_tcpSocket, m_tcpSocket);
connect(m_tcpSocket, SIGNAL(disconnected()), m_disconnectedSignalMapper, SLOT(map()));
m_disconnectedSignalMapper->setMapping(m_tcpSocket, m_tcpSocket);
}
the sever construct function:
ServerModule::ServerModule(QObject * parent) : QTcpServer(parent),m_readyReadSignalMapper(new QSignalMapper(this)),m_disconnectedSignalMapper(new QSignalMapper(this))
{
connect(m_readyReadSignalMapper, SIGNAL(mapped(QObject *)), this, SLOT(SlotReadyRead(QObject *)));
connect(m_disconnectedSignalMapper, SIGNAL(mapped(QObject *)), this, SLOT(SlotDisconnected(QObject*)));
......other code
}
SlotReadyRead and SlotDisconnected functions are every normal,it convertsQObject* socketObject to QTcpSocket *socket and then do some work.
So i have learned that if write like aboving connect function with specific connect mode
Qt::DirectConnection
Qt::QueuedConnection
Qt::BlockingQueuedConnection
if using single thread,only first mode and second mode can be used . And use first mode, it's synchronous ,if second, it's asynchronous. My program default using first mode, so the signals -slots are connected synchronous.
So here is my worry:
1. How about the single thread performance for handling multiple sockets?can it reach 500 connection /per second concurrency?what's the max connected can be handled?
2. if at the same time,multiple sockets are ready to read then called qt core to send readyRead signals, the QSignalMapper can handle it properly?
3. should I connect socket and QSignalMapper using QueuedConnection mode, because this connecting is not connected immediately, it's using event queue and postEvent to connect. so its asynchronous. Is in this situation,the concurrency request can be handled?
First a few issues with your code:
QSignalMapper just adds complexity to your code
Don't use a member variable for QTcpSocket, you will be overwriting it every time and chances are that you might use an invalid pointer
If you are not doing something complex or using QSslSocket don't subclass QTcpServer, just connect to the newConnection() signal and call nextPendingConnection()
Now to the connect part of your questioning you should read https://woboq.com/blog/how-qt-signals-slots-work.html in short:
Qt::DirectConnection - means once the signal is emitted the slot will called immediately, if the object that has the slot lives in another thread it will be called in the caller thread. This is used if Qt::AutoConnection is used and both objects live in the same thread.
Qt::QueuedConnection - means that when the signal is emitted it will create an event and be put on the event loop to be dispatched once you return to the event loop, this is useful for different threads as the slot will called on the thread that the object lives in. This is NOT what you want here, nor how QTcpSocket should be used (read the docs).
Qt::BlockingQueuedConnection - is very rare to use this one, this like the above puts the event on the event loop of the other thread, but it blocks until the slot was called.
The only "Sync" method is the blocking one, because it would block, but that doesn't mean it's a problem, you can have a non-gui thread that blocks waiting for the reply of the gui thread while asking the user for a password for example.
To the questions now:
UPDATED 1 and 3 for more clarification
Performance really depends on what these sockets will do, how long each will take to process the request and send a reply, in Cutelyst Web Framework a single thread on an i5 can process up to 100K req/s (returning a 'Hello Wolrd!' string HTTP response), the maximum number depends of concurrent connections will be limited by max ports available, memory available to allocate memory and of course if it's CPU intensive the clients will have a long time waiting.
The most common way is to call sender() on your slot, due a small hit on performance (due sender() call) it's faster to use a lambda:
void Parser::readyRead() {
auto socket = qobject_cast<QTcpSocket*>(sender());
...
}
Or with a lambda:
connect(sock, &QTcpSocket::readyRead, [sock] () {
// use sock obj here
});
Again QSignalMapper is not what you want, you should call sender() to get the QTcpSocket or use a lambda capturing the socket object (this is a little faster)
No shouldn't used QueuedConnection connection on your QSignalMapper, because that will cause an unneeded overhead due the fact that it will put the event on the event loop queue and it will be processed later, it might also cause weird bugs due the way QTcpSockets handle data (you must consume all the bytesAvailable() on readyReady since if no extra data arrives readyRead() signal is not emitted again.
I tried to put a QWebSocket connection into a QThread
QThread *thread = new QThread;
connect(&websocket,&QWebSocket::connected,this,&Widget::onWsConnect);
websocket.moveToThread(thread);
connect(thread, &QThread::finished, &websocket, &QObject::deleteLater);
websocket.open(wsUrl);
thread->start();
The program compiled without errors and is running normal, but when it tried to connect to the websocket server throws this error:
QObject::connect: Cannot queue arguments of type 'QAbstractSocket::SocketState'
(Make sure 'QAbstractSocket::SocketState' is registered using qRegisterMetaType().)
When I do
websocket.open(wsUrl);
without threading the connection works fine.
Any ideas?
If you want to send your object through queued signal/slot connections, you should use qRegisterMetaType<T>(). Just call it before opening the socket some where in the constructor :
qRegisterMetaType<QAbstractSocket::SocketState>();
The previous (Nejat's) answer is good as direct answer on how to attach the signal to slot in this case. But why do you want to start the web-socket on an additional thread? I start that same Qt WebSocket from main thread and it does no block it. The time to start that type of socket itself is negligible. I guess websocket uses some kind of OS non-blocking IO (likeliest) or spawns another thread internally (less likely). Other than blocking or doing massive computation you probably don't have a good reason for spawning a new thread and then taking care of managing it and additional communication overhead.
My suggestion would be to maintain a list of open websocket connections, and when a particular connection gets a request, spawn a thread to handle the request and continue processing new connections/requests on the main thread. Then, when the thread is done processing the request, it signals the main thread that it's done, along with the response. The main thread would then receive the response from the thread and send it out over the open connection. You could use std::async and std::future to accomplish this.
My aim is to receive messages from a serial device without blocking the main thread (GUI) and to try to separate the platform-dependent logic (GUI and serial port) from the business logic (processing the messages) for ease of porting to other platforms
Context: I'm using Qt, and the QtSerialPort module. The message protocol is simple, 0xff is used to end each message.
I've found 4 solutions so far:
Method 1:
Using one thread to read a serial port and fill a buffer
Using another thread to read the buffer, extract valid messages (into another buffer? not sure how this will work yet)
Using yet another thread to parse the messages
Method 2:
Using one thread to read a serial port, and extract valid messages into a buffer
Using another thread to parse the messages
Method 3:
Using one thread to read a serial port, extract a valid message, and block till that message is processed, making use of QtSerialPort's internal read buffer to buffer incoming data
Method 4:
Using the main thread to asynchronously read serial port, extract a valid message, and for each message, spawn a new thread to process them
Methods 1,2 and 3 differ by the number of threads the general workload is split up into, though I don't know which is best.
I'm currently using method 4, which is horribly inefficient and doesn't work well on lower-end computers, due to the enormous number of threads being spawned, and every time I move or interact with the GUI, serial communication halts. Spawning a thread for each message also makes the order of the messages non-deterministic, which hasn't been a major problem so far...
Are there other methods, what are the pros (if any) and cons of each, and which is the best to use? Thanks!
EDIT: A problem with processing messages in the main thread is that interacting with GUI (even moving the window) would block the message processing function. Is there any way around this?
I think there are two main advantages that you can obtain by using multithreading:
Avoiding poor GUI performance due to the GUI-handling routines being held off by the serial port processing routine
(perhaps more important) Avoid loss of serial data caused by buffer overflow when the GUI routines hold off the serial-data-reading routine for too long.
You should only need to spawn a single thread. Just have that thread read data from the serial port as it comes in (by connecting the QSerialPort's readyRead() signal to a slot that calls read() on the QSerialPort object), and then emit a signal (with a QByteArray argument) whenever it wants to send some serial data to the GUI. Your main/GUI thread can receive the data via a QueuedConnection that will not block either the serial-thread or the main/GUI thread.
That's pretty much all there is to it; the only other thing to worry about is a clean shutdown. Be sure to have another cross-thread signal/slot connection to the QThread's quit() slot, so that when it's time to quit, you can emit that signal and then call wait() on the QThread to wait for it to respond by going away. Once wait() has returned you can safely delete the QThread object.
You can avoid additional threads at all by simply relying on Qt event loop (so far the main thread, the one also handling the GUI to be clear, will be blocked only when a message is actually received by the serial port).
Otherwise if you want to completely handle serial port in a dedicated thread, then the solution is to implement a class deriving from QThread and then override the run() function with something like this:
void MyClass::run()
{
QSerialPort port;
// ... serial port initialization here
// Connect signals/slots
connect(&port, SIGNAL(readyRead()), this, SLOT(readData()));
port.open();
// Start a new message loop on this thread
exec();
}
Where readData is a function implemented in MyClass for handling the received data. Since port is owned by the new thread (being created in run()) then its events will be handled by the thread itself (in a completely independent manner with respect to the main thread).
If you want at some point communicate something to the main thread (e.g.: you received something on serial which should cause a change in your GUI) then you can still use Qt's signals/slots. Simply implement a signal on MyClass and implement a slot on an object handled by the main thread (e.g.: your main form): then simply connect the signal for MyClass and the slot on your main form and you're done: signals/slots is THE solution for cross-thread communication in Qt.
You could also avoid using any (additional) threads and take advantage of Qt event loop. Read about events, QioDevice; then Qt would pass your device file descriptor to its multiplexing loop (e.g. to poll(2)....); probably QSocketNotifier should work (on Posix) on a non-socket file descriptor like a serial device.
Details are probably OS specific
The title is very cryptic, so here goes!
I am writing a client that behaves in a very synchronous manner. Due to the design of the protocol and the server, everything has to happen sequentially (send request, wait for reply, service reply etc.), so I am using blocking sockets. Here is where Qt comes in.
In my application I have a GUI thread, a command processing thread and a scripting engine thread. I create the QTcpSocket in the command processing thread, as part of my Client class. The Client class has various methods that boil down to writing to the socket, reading back a specific number of bytes, and returning a result.
The problem comes when I try to directly call Client methods from the scripting engine thread. The Qt sockets randomly time out and when using a debug build of Qt, I get these warnings:
QSocketNotifier: socket notifiers cannot be enabled from another thread
QSocketNotifier: socket notifiers cannot be disabled from another thread
Anytime I call these methods from the command processing thread (where Client was created), I do not get these problems.
To simply phrase the situation:
Calling blocking functions of QAbstractSocket, like waitForReadyRead(), from a thread other than the one where the socket was created (dynamically allocated), causes random behaviour and debug asserts/warnings.
Anyone else experienced this? Ways around it?
Thanks in advance.
I'm assuming that you're using QThread for the threading operations. If so, you can either a) use queued signal-slot connections; or b) explicitly use the QThread's event loop by creating a custom event type, posting that event in your scripting engine, and then having the client class handle those events.
example for a)
class ClientThread : public QThread
{
..stuff..
public slots:
waitForReadyRead();
};
class ScriptEngineThread : public QThread
{
..other stuff..
signals:
void requestWaitForReadyRead();
};
// In the ScriptEngineThread implementation...
ScriptEngineThread::setupClient()
{
connect(this, SIGNAL(requestWaitForReadyRead()),
client_, SLOT(waitForReadyRead()),
Qt::QueuedConnection);
}
Then, whenever you want to do the socket operations, just emit ScriptEngineThread::requestWaitForReadyRead();. The major difficulty is, I assume, you need the scripting thread to wait for some socket operation to be done. In this case you'll need to fire signals back and forth between the threads, causing some circular dependancy.
For alternative b, it would require a little more coding work, but you could:
Create your own subclasses of QEvent
Create a class to operate as a middleman, posting and handling each of your QEvents and emitting signals to communicate with the threads - each thread can have an instance of this
Connect the client and script engine to the event signals it cares about.