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
Related
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 have two process, ProcessGUI and ProcessMaster. My both processes will do some action in some conditions. Suppose once some thing happens in Master process, GUI process has to display some thing. I want to indicate that by changing the event fd. Is there any way, where I can share an event fd between two process.
There are a number of ways to achieve what you want.
The first one that popped into my head is using sendmsg to share the eventfd over a socket.
That approach is feasible, but it requires both processes to open a socket.
One other approach is using signals. There are 2 signals that can be used as "User Signals"; USR1 & USR2, you can set up one process to catch a user signal, and the other to send it (kill it, to be more accurate).
The last thing I can think about is using a socket and (e)polling it. To be honest, it's just like the first approach, but without sharing the FD over the socket.
You can use the Linux signals to communicate the two processes. Here you have some examples: Linux signals.
One of your processes generates a signal with the raise() method and the other registers a signal handler to react the event with signal() function.
I have a QThread that reads from a socket and sends a signal (QT signal) when there are any data available.
This would be easy with blocking read(2), but i need to be able to stop the thread from outside without waiting for too long.
If I were using pthread I would use pselect and pthread_kill(thread_id, some_signal), but QThread doesn't
seem to have any similar methods. And adding a dependcy on pthread to this project doesn't seem to elegant.
I also don't want to use the other ugly methods like constantly trying to read from the socket with some relatively small timeout.
Edit: The sockets are not TCP, but bluetooth L2CAP.
A not too elegant, but simple and working solution:
Create a pipe and let select wait for either the pipe or my socket. This way I can stop the wait anytime by writing something to the pipe.
Instead of dealing with the threading yourself you can use the asynchronous interface of QTcpSocket. Check out the Fortune Client example.
You can send a signal to the terminate() slot of your QThread. This will stop your thread according to OS scheduling policies.
Hey I am not sure if this has already been asked that way. (I didn´t find anwsers to this specific questions, at least). But:
I have a program, which - at startup - creates an Login-window in a new UI-Thread.
In this window the user can enter data which has to be verified by an server.
Because the window shall still be responsive to the users actions, it (ofc it´s only a UI-thread) shall not handle the transmission and evaluation in it´s own thread.
I want the UI-thread to delegate this work back to the main thread.
In addition: The main thread (My "client" thread) shall manage all actions that go on, like logging in, handle received messages from the server etc... (not window messages)
But I am not sure of how to do this:
1.) Shall I let the UI-Thread Queue an APC to the main thread (but then the main thread does not know about the stuff going on.
2.) May I better use event objects to be waited on and queues to transmit the data from one thread to another?...
Or are there way better options?
For example: I start the client:
1. The client loads data from a file and does some intialization
The client creates a window in a new thread which handles login data input from the user.
The Window Thread shall notifiy and handle the , that has been entered by the user, over to the client.
The Client shall now pack the data and delegate the sending work to another object (e.g. CSingleConnection) which handles sending the data over a network (of course this does not require a new thread, because it can be handle with Overlapped I/O...
One special receiver thread receives the data from the server and handles it back to the client, which - in turn - evaluates the data.
If the data was correct and some special stuff was received from the server, the main thread shall signal the UI thread to close the window and terminate...
The client then creates a new window, which will handle the chatting-UI
The chatting UI thread and the Client thread shall communicate to handle messages to be sent and received...
(Hope this helps to get what I am trying)...
It all depends on what you are prepared to use. If you are developing with Qt, their signals and slots are just the thing to do such a communication. They also supply a network library, so you could easily omit the receiver thread because their network classes do asynchronous communication and will send a signal when you have data, which means your thread does not need to be blocked in the mean time.
If you don't want to use Qt, boost also supplies thread safe signals and slots, but as far as I understand it their slots will be run in the context of the calling thread...
Anyways, I have used Qt sig and slots with great satisfaction for exactly this purpose. I wholeheartedly agree GUI's shouldn't freeze, ever.
I don´t know wether this is good style or not (anwsering Your own question):
But I think I go with Event Objects and two queues (one for the connection between Client and Connection, and one to communicate Client and UI)...
I have a Qt/C++ application, with the usual GUI thread, and a network thread. The network thread is using an external library, which has its own select() based event loop... so the network thread isn't using Qt's event system.
At the moment, the network thread just emit()s signals when various events occur, such as a successful connection. I think this works okay, as the signals/slots mechanism posts the signals correctly for the GUI thread.
Now, I need for the network thread to be able to call the GUI thread to ask questions. For example, the network thread may require the GUI thread to request put up a dialog, to request a password.
Does anyone know a suitable mechanism for doing this?
My current best idea is to have the network thread wait using a QWaitCondition, after emitting an object (emit passwordRequestedEvent(passwordRequest);. The passwordRequest object would have a handle on the particular QWaitCondition, and so can signal it when a decision has been made..
Is this sort of thing sensible? or is there another option?
Using signals to send messages between threads is fine, if you don't like using the Condition Variable, then you can send signals in both directions in a more-or-less asynchronous manner: this might be a better option if you want to continue processing network stuff while you wait for a reply from the GUI.