Signals and slots between objects in different threads in Qt - c++

Basically, I've the next code:
class serverTCP : public QObject
{
// Other methods...
signals:
void newInstructions(QJsonDocument jDoc);
public slots:
void responseObtained(QJsonDocument jDoc);
}
class gatherModbus : public QObject
{
// Other methods...
signals:
void responseReady(QJsonDocument jDoc);
public slots:
void executeInstruction(QJsonDocument jDoc);
void myprocess() {
while(true)
{
// Write and read Serial Port
// Save data in json
}
};
}
void main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
int netsNumber = 2; //In reality this is dynamic. It's only a example
serverTCP *server = new serverTCP;
gatherModbus * gather = new gatherModbus[netsNumber];
QThread * threads = new QThread[netsNumber];
// more necessary code...
for(int i = 0; i < netsNumber; i++)
{
gather[i].moveToThread(threads[i]);
QObject::connect(&server, SIGNAL(newInstructions(QJsonDocument)),
&gather[i], SLOT(executeInstruction(QJsonDocument)));
QObject::connect(&gather[i], SIGNAL(responseReady(QJsonDocument)),
&server, SLOT(responseObtained(QJsonDocument)));
QObject::connect(&threads[i], SIGNAL(start()),
&gather[i], SLOT(myprocess()));
// Other signals needed between the objects 'gather' and 'threads'
threads[i].start();
}
a.exec();
}
The problem is that the connections between objects 'server' and 'gather' do not work. The object 'server' is in the same thread as the 'main' function but objects 'gather' have moved to other threads.
What have I to do to make both objects can communicate properly?
My purpose is that the 'server' must be able to send a signal to all objects 'gather' there are. In each of the objects 'gather' must execute the slot and return the 'server' response if any.
If I set up the connection to be the type Qt::DirectConnection slots running on the same thread as the 'main' function and object 'server' and that does not interest me.
Any help or suggestions will be appreciated.

All is in Qt documentation.
First, read that.
Then if you're not satisfied, you can use QCoreApplication::postEvent() (for more informations you need : here)
Both signals/slots (QObject:connect()) and QCoreApplication::postEvent() are thread-safe and can solve your problem.
So events and signal/slots are two parallel mechanisms accomplishing the same things, in general an event will be generated by an outside entity (e.g. Keyboard, Mouswheel) and will be delivered through the event loop in QApplication. In general unless you set up the code you will not be generating events. You might filter them through QObject::installEventFilter() or handle events in subclassed object by overriding the appropriate functions.
Signals and Slots are much easier to generate and receive and you can connect any two QObject subclasses. They are handled through the Metaclass (have a look at your moc_classname.cpp file for more) but most of the interclass communication that you will produce will probably use signals and slots. Signals can get delivers immediately or deferred via a queue (if you are using threads) A signal can be generated

Your demo code seems OK. That's how we organize our current project. You'd better provide more detailed codes if necessary to explain your problem.
BTW, after reading your interests, I'd recommend you the QtConcurrent module which seems fitting your interest better.

Huh... Your code is not ok. This is the source of all your trouble
void myprocess() {
while(true)
{
// Write and read Serial Port
// Save data in json
}
};
If you want the slots newInstructions and responseObtained slots to ever run, myprocess should not be an infinite loop. You need to :
Modify myprocess such that once it is done writing and reading currently available data, it completes
Have a mechanism to know that new processing need to be done. For instance, if you are using a QIODevice subclass (socket, input stream, etc...) you have the signal QIODevice::readyRead() which will notify you there is new data to read from the device. I suspect your newInstructions is supposed to do just that.
connect this mechanism to another call to myprocess to allow the processing to start again
Edit : Given your comment, this is a way to modify the infinite while loop without too much modification.
void myprocess() {
make_one_processing_round();
if(should_continue_processing())
{
QMetaObject::invokeMethod(this, &gatherModbus::myprocess, Qt::QueuedConnection);
}
};
QMetaObject::invokeMethod will schedule this method for execution at the back of the thread QEventLoop queue. Which means other slots can execute.

I can solve my problem adding the next line in the end of "myprocess" method:
QCoreApplication::processEvents(QEventLoop::AllEvents);
The final code of this method is this:
void myprocess() {
while(true)
{
// Write and read Serial Port
// Save data in json
// New line:
QCoreApplication::processEvents(QEventLoop::AllEvents);
}
};
With this line I get that events will processed if any. I don't known if it is the best solution, but it works as wanted.
Thanks to all of you for your help and answers.

Related

Prevent event loop blocking in modal dialog

I'm developing an application where a user may parse some binary files. Once he clicks the "parse"-button, he first may select some files, which are parsed afterwards. While the application is processing the files, I'd like to display a modal dialog, which informs the user about the progress (QProgressBar bar) and the already parsed files (QListView list / listModel).
My current approach is to override the exec()-method of a QDialog-sublcass. This way I could just call
parseAssistant.exec()
The current implementation looks like this:
class ParseAssistant : public QDialog { public: int exec(); };
int ParseAssistant::exec()
{
bar->setMaximum(files.size());
this->show();
this->setModal(true);
for (int i = 0; i < files.size(); i++) {
PluginTable* table = parser.parse(files[i]);
// do something with the table
// saveTableintoDB();
// update GUI
// bar->setValue(i);
// listModel->insertRow(0, new QStandardItem(files[i]));
}
this->hide();
return QDialog::Accepted;
}
After this (blocking) method has run, the user either has parsed all files or canceled the progress somewhere. To achieve this I attempted to use QApplication::processEvents in the while-loop (which feels kinda laggy as it's only progressed when a file has finished parsing) or to outsource the heavy calculation(s) to some QConcurrent implementation (::run, ::mapped). Unfortunately, I don't know how to return the program flow back to the exec() method once the QFuture has finished without relying on some CPU-intense loop like:
while (!future.isFinished()) { QApplication::processEvents(); }
Is there a smarter approach to having a modal dialog, which runs a heavy calculation (which may be canceled by the user) without blocking the eventloop?
I wouldn't subclass Qdialog, in the first place, but just use a QFutureWatcher and connect the watcher finished signal to the dialog close slot, this way:
QDialog d;
QFutureWatcher<void> watcher;
QObject::connect(&watcher, &QFutureWatcher<void>::finished, &d, &QDialog::close);
QFuture<void> future = QtConcurrent::run(your_parse_function);
watcher.setFuture(future);
d.exec();
//control returns here when your_parse_function exits
The parse function could be a method in a QObject derived class, like this:
class Parser : public QObject
{
Q_OBJECT
public:
void parse()
{
for (int i = 0; i < files.size(); i++) {
PluginTable* table = parser.parse(files[i]);
emit fileParsed(i, files.size);
// ...
}
}
signals:
void fileParsed(int id, int count);
};
You can connect the fileParsed signal to a slot of choice, and from there set the progress bar value accordingly.
My personal approach would be:
create a separate thread and do the processing there (QThread; std::thread should do the trick as well)
provide a signal that informs about the file currently being processed
possibly another signal informing about progress in %
another signal informs that processing is done, emitted just before the thread ends
provide your dialog with appropriate slots and connect them to the signals (as different threads involved, make sure connection type is Qt::QueuedConnection)

QT - Mainwindow doesn't update unless it's closed

I'm trying to update the main window by calling updateGUI function in a thread every 500 ms. The window is displayed but not updated with the new values unless I close the window. When I do so, a new window is opened with the new value. I found this question but it didn't answer my question. I knew that (as stated in qt documentation)
QApplication::exec enters the main event loop and waits until
exit() is called.
I tried to use processEvents() but the main window is opened and closed repeatedly and very fast that I can't even see it. Here is my code:
float distanceToObject;
bool objectDetected;
Modes currentMode;
void timerStart(std::function<void(void)> func, unsigned int interval)
{
std::thread([func, interval]()
{
while (true)
{
auto x = std::chrono::steady_clock::now() + std::chrono::milliseconds(interval);
func();
std::this_thread::sleep_until(x);
}
}).detach();
}
int updateGUI(void)
{
int argc = 0;
char **argv = NULL;
QApplication a(argc, argv);
MainWindow w;
// Set text of a label
w.setDistance(QString::number(distanceToObject));
// Also update objectDetected and currentMode values
w.show();
//a.processEvents();
return a.exec();
}
void sendMsg(void)
{
// Send heartbeat signal to another device
}
void receiveMsg(void)
{
// Read messages from the other device and update the variables
// These two values change continuously
objectDetected = true;
distanceToObject = 5.4;
}
void decide(void)
{
// The core function of the program. Takes relatively long time
// Run a decision-making algorithm which makes decisions based on the values received from the other device.
// Update some variables according to the made decisions
currentMode = Auto;
// Execute functions according to the made decisions.
setMode(currentMode);
}
int main(void)
{
timerStart(updateGUI, 500);
timerStart(sendMsg, 1000);
timerStart(receiveMsg, 10);
timerStart(decide, 500);
}
How can I update the main window with the variables' values correctly?
Your thread does not update the MainWindow, but it does create an entirely new QApplication and MainWindow on every iteration. Your thread should be stuck inside QApplication::exec until you quit the application (e.g. by closing the window). Only then should your thread's loop make further progress.
In general, you must be very careful when doing updates from outside the main thread, since typically GUI operations must be performed inside the main thread.
Think about using QThread, which already comes with its own event loop, which you can use to notify/update your window using a respective slot.
Without further details about what you are actually trying to achieve, it is not possible to give you further direction. I, at least, recommend that you create your QApplication and MainWindow inside the main thread (e.g. main). Then it depends what you are trying to 'update'. If you need to progress some data, then you can do that within your second thread and send the results to your MainWindow instance using signal-slot. If you need to draw onto the window, then this either has to be done in the main thread directly, or you might find a way to render into a separate buffer (i.e. QImage) from within your thread and then send this buffer to the main thread for drawing it into the window.
I try to sketch how something like this can be done. Notice, however, that this it neither complete nor compilable, but merely an outline.
First, you have your MainWindow and add to it a signal, that notifies all observers to start doing their work (will become clear in a moment). Furthermore, you add slots that will be invoked whenever one of your values changes. Those slots run in the main thread (and are members of the MainWindow) and thus can update the window however they need to:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
// constructors and stuff
void startWorking()
{
emit startWorkers();
}
public slots:
void onModeChanged(Modes m)
{
// update your window with new mode
}
void onDistanceChanged(float distance)
{
// update your window with new distance
}
signals:
void startWorkers();
};
Next, you build a Worker class, that encapsulates all the 'background work' you like to do (basically what your thread did in your original code):
class Worker : public QObject
{
Q_OBJECT
public:
// constructors and stuff
public slots:
void doWork()
{
while(!done)
{
// do stuff ...
Modes m = // change mode
emit modeModified(m);
// do stuff ...
float distance = // compute distance
emit distanceModified(distance);
// do stuff ...
}
}
signals:
void modeModified(Modes m);
void distanceModified(float distance);
};
Note, that Worker must inherit QObject and that your doWork method must be a public slot. Furthermore, you add a signal for each of the values you like your MainWindow to be informed about. No implementation for them is needed, since it is generated by the Qt MOC (Meta Object Compiler). Whenever one of the respective values changes, simply emit the corresponding signal and pass the new value.
Lastly, you put everything together:
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
MainWindow window;
// create a worker object
Worker* worker = new Worker;
// connect signals and slots between worker and main window
QObject::connect(worker, &Worker::modeModified,
&window, &MainWindow::onModeChanged);
QObject::connect(worker, &Worker::distanceModified,
&window, &MainWindow::onDistanceChanged);
QObject::connect(&window, &MainWindow::startWorkers,
worker, &Worker::doWork);
// create a new thread
QThread* thread = new QThread;
// send worker to work inside this new thread
worker->moveToThread(thread);
thread->start();
// show window and start doing work
window.show();
window.startWorking();
// start main loop
int result = app.exec();
// join worker thread and perform cleanup
return result;
}
Alright, let's go through it. First, you create your QApplication and MainWindow inside your main thread. Next, create an instance of your Worker object (could create multiple here). Then you connect the signals of the worker to the slots of the window and vice versa. Once these connections are established, whenever you emit a signal, the connected slot is invoked by Qt (and passed values are transmitted). Notice, that this connection works across thread boundaries. Whenever a signal is emitted from a thread different then the receiving object's thread, Qt will send a message, which is processed in the receiving object's thread.
Then you tell Qt that you want your worker to live inside another thread using QObject::moveToThread. See here for a very detailed explanation of how to correctly use QThread and objects inside it.
The rest is then simple. show your window and start processing. Here different ways are possible. I just call the startWorking method here, which then emits the startWorkers signal, which is connect to the worker's doWork method, such that doWork will start executing after this signal is received by the other thread.
You then call QApplication::exec which runs the main thread's event loop, where all these signals are processed by Qt. Once your application is closed (e.g. by calling quit or closing the main window) the exec method returns and you are back in main. Notice, that you need to correctly close the thread (e.g. by sending an addition signal that stops the while loop) and join it. You also should delete all the allocated objects (worker, thread). I omitted this here for simplicity of the code example.
Answering your Question
I have many functions, e.g., updateClips and mavReceive that should be called periodically and run independently from each other. I should create a different Worker class for each function, as each has different signals, and a QThread object for each of these functions, right? I don't need startTimer() anymore? If yes, how can I control the calling interval for each function (used to be done in startTimer()
from the comment:
The answer greatly depends on what exactly you mean by "should be called periodically". Who is supposed to call them? The user? Or should they just be executed periodically?
So in principle, you can have multiple workers in one thread. However, if they are supposed to do work all the time (spin in a while loop) it does not make sense, since one is running and all others are blocked. In that case you would have one thread for each worker.
If I understand you correctly, you are interested in updating something periodically (e.g. every 500ms). In that case I highly recommend using the QTimer. You can set an interval and then start it. The timer will then periodically emit the timeout signal, which you can connect to whatever function (more precisely slot) you want to have executed.
An updated version of the Worker could look like this:
class Worker : public QObject
{
Q_OBJECT
public:
Worker()
{
QObject::connect(&modeTimer_, &QTimer::timeout,
this, &Worker::onModeTimerTimeout);
QObject::connect(&distanceTimer_, &QTimer::timeout,
this, &Worker::onDistanceTimerTimeout);
modeTimer_.start(500); // emit timeout() every 500ms
distanceTimer_.start(100); // emit timeout() every 100ms
}
public slots:
void onModeTimerTimeout()
{
// recompute mode
Modes m = // ...
emit modeModified(m);
}
void onDistanceTimerTimeout()
{
// recompute distance
float distance = // ...
emit distanceModified(distance);
}
signals:
void modeModified(Modes m);
void distanceModified(float distance);
private:
QTimer modeTimer_;
QTimer distanceTimer_;
};
Notice, the connections established in the constructor. Whenever one of the timers times out, the connected slot is invoked. This slot then may compute whatever it needs to and afterwards send the result back to the MainWindow in the main thread using the same signal as before.
So, as you see, you can have multiple timers / re-computations / update signals within one Worker (and thus, one thread). However, the crucial point for an implementation is, how long the computations take. If they take very long (e.g. nearly as long as the intervals) then you should think about using multiple threads to speed up the computation (meaning: perform one computation in each thread). As I slowly seem to get a clearer picture of what you want to achieve, I am wondering whether it is only about these periodic updates that you 'misused' the thread for in your question. If this is indeed the case, then you do not need that thread and Worker at all. Then simply add the timers to your MainWindow and connect their timeout signal to the respective slot of the MainWindow directly.

Qt create a dialog that waits for a network event

I am writing the client for a client/server application. The clients are supposed to login using a login window. If the login is successful, a "waiting" window appears (this is just a window that contains a label). On the server side there is a barrier that waits for n clients to be logged in; when this happens, a message is broadcasted, the waiting window is supposed to close and a new window appears for every client.
The networking interface is implemented by me, using low-level functions, not the functionality provided by Qt.
The actual waiting loop is something like this:
char buffer[256];
while (strcmp(buffer, "proceed"))
read(sockfd, buffer, 256);
The problem is that if I start this loop in the main thread, the application blocks, for obvious reasons.
How can I make this loop run and not block the application, and close the dialog when it ends?
Later edit: I did also attempt to use QThreads, but, for reasons which I don't fully understand yet, the application still crashes:
class WaitLoop : public QThread {
public:
WaitLoop(NetworkHandler &network) : network(network) {}
private :
NetworkHandler &network;
void run() {
this->network.waitForGameStart();
}
};
In the wait dialog constructor:
WaitLoop *waitLoop = new WaitLoop(network);
connect(waitLoop, SIGNAL(finished()), this, SLOT(gameStartSlot()));
waitLoop->start();
The application still crashes using this approach.
The sanest way to approach this would not be using low-level functions, because you aren't writing in C. Use at least QAbstractSocket to wrap a sockfd. The setSocketDescriptor method lets you do it.
Your code then becomes non-blocking and asynchronous:
class Controller : public QObject {
Q_OBJECT
QStateMachine m_sm;
QState s_init{&m_sm}, s_proceeding{&m_sm};
QAbstractSocket m_socket;
Q_SIGNAL void proceed();
Q_SLOT void onData() {
auto data = m_socket.readAll();
if (data.contains("proceed")) proceed();
}
public:
Controller(QObject * parent = 0) : QObject(parent) {
connect(&m_socket, &QIODevice::readyRead, this, &Controller::onData);
s_init.addTransition(this, &Controller::proceed, &s_proceeding);
m_sm.setInitialState(&s_init);
m_sm.start();
}
bool setup(quintptr fd) {
return m_socket.setSocketDescriptor(fd);
}
};
Through the use of a state machine, it's easy to add more states, react to their transitions (see QState::onEntry signal, etc.), and ensure that the behavior is correct. Fleshing out a UML statechart forces you to think about handling corner cases, etc. See this answer for a full example.

How can I provide feedback from a non-Qt C++ library class to a Qt GUI?

I am developing a C++ class library for some computing-intensive tasks (machine vision).
// I am a part of a Qt-agnostic library
class Cruncher
{
/* ... */
public:
void doStuff();
};
Then there's a Qt GUI using that library. I'm creating a worker thread to call the heavy-lifting routines from the library:
// I am a part of a Qt-based GUI which utilizes the library
class Worker : public QThread
{
/* ... */
protected:
virtual void run()
{
/* ... */
Cruncher c;
for (int i = 0; i < count; ++i)
c.doStuff(); // takes some time, and while it's working
// it should communicate status changes which should
// become visible in the GUI
}
};
Now inside doStuff() a lot happens and I want to provide some feedback to the user on what is going on without waiting for doStuff() to return. For one, maybe some finer progress reporting than just increasing the meter by one step after a each call to doStuff(). Also, doStuff() may encounter non-critical failures which let it continue a part of the work, but I'd like a message to appear in the GUI when this happens as Cruncher is working (and Worker is currently busy with a call to doStuff()).
I want the library to remain Qt-independent so I'm not willing to add signals and slots to Cruncher. Any other way to enable it to provide feedback to the GUI to report on its work when it's not a Qt class?
I was considering creating a QTimer which would poll some "status" and "errorMsg" members of Cruncher at fixed intervals while Worker is running, but this seems highly sub-optimal.
I am posting my own answer because though I took #Nim's advice, I'd like the answer to be a little more verbose and hence more useful if someone should have the same problem.
I created the skeleton of a message dispatcher in the library:
// doesn't need to know about Qt
class MessagePort
{
public:
virtual void message(std::string msg) = 0;
};
Next, I added a handle to this object to Cruncher and spiced doStuff() with occasional calls to message():
// now with Super Cow powers!
class Cruncher
{
protected:
MessagePort *msgPort_;
public:
Cruncher(MessagePort *msgPort) : msgPort_(msgPort) {}
void doStuff()
{
while(...)
{
/*...*/
msgPort_->message("Foo caused an overload in Bar!");
}
}
};
Finally, I crafted an implementation of MessagePort inside the GUI using all necessary Qt goodness:
class CruncherMsgCallback : public QObject, public MessagePort
{
Q_OBJECT
public:
CruncherMsgCallback() : QObject(), MessagePort()
{
connect(this, SIGNAL(messageSignal(const QString &)),
GUI, SLOT(messageShow(const QString &)),
Qt::QueuedConnection);
}
virtual void message(std::string msg)
{
emit messageSignal(QString::fromStdString(msg));
}
signals:
void messageSignal(const QString &msg);
};
Finally when the Worker creates an instance of Cruncher, it also gives it a pointer to a working MessagePort:
class Worker
{
protected:
virtual void run()
{
CruncherMsgCallback msgC;
Cruncher c(&msgC); // &msgC works as a pointer to a
// generic MessagePort by upcasting
c.doStuff(); // Cruncher can send messages to the GUI
// from inside doStuff()
}
};
Use a callback function (class) etc, and pass that in during construction. Things you need to report, report via that callback.
You can safely emit signals from the run() method, I think that's the best way to pass information from worker thread to the main thread. Just add the signals to your QThread subclass (avoid adding slots, if you're at all unsure how QThread threading works).
Better make the connections from these signals explicitly queued, to avoid problems. Though the default, automatic connection type should also work and do Queued signal emit, but I think it's better to be explicit in cases like this. Actually also direct signals should work as such, but then you have to take care of thread safety yourself instead of letting Qt handle it for you, and you can't connect to slots which use any of the QtGui classes which only work in the main thread, so it's better to stick to queued connections.
To pass simple information to the run() method, and if immediate reaction is not needed, maybe use a few shared QAtomicInt variables or something like that as flags, which the worker thread checks when convenient. Slightly more complex method, still requiring polling, is to have shared data structure which you protect with mutex. More complex way of communicating to that direction would involve some kind of message queue (just like Qt uses in the event loop of the main thread, when you emit signal to that direction).

Qt Getting Response from SoapRequest

Consider the following in Qt using QtSoap lib:
QtSoapHttpTransport http;
http.setHost("XXXX",3333);
connect(&http, SIGNAL(responseReady()), this, SLOT(getResponse()));
now there is a method i want to call which is:
QtSoapMessage request;
request.setMethod("test");
request.addMethodArgument("xxx","zzzz",xxx);
request.addMethodArgument("xx","xx",xx);
http.submitRequest(Request, "/api/soap");
now i want to have something like this :
QString GetTest(){
while(http.isBusy); // no such a thing as isbusy
return http.getResponse().returnValue().toString();}
or any technique i can use to get the return value or wait for it and get it..
Thanks in advance...
I don't see a problem. The QtSoapHttpTransport reference already has a nice simple example.
If you want to have a getter that blocks and returns only when the response is received, doing active wait (your while loop) is absolutely not a way to go.
You already connect the responseReady signal to your slot, so the only missing thing would be to have a synchronization point that blocks your thread calling getTest until this slot is executed.
class Messenger : public QObject {
Q_OBJECT
public:
Messenger() { /* ... your initialization code with connect ... */ }
void sendRequest() { /* ... your sending code ... */ }
QString getTest() // call this from a worker thread to wait
{ // for a response to arrive and retrieve it
QMutexLocker lock(&responseMutex);
responseReady.wait(&responseMutex);
return http.getResponse().returnValue().toString();
}
public slots:
void getResponse() { // slot called by Qt event loop when response arrives
responseReady.wakeAll();
}
private:
QtSoapHttpTransport http;
QWaitCondition responseReady;
QMutex responseMutex;
};
Note that this design only makes sense if you have a multithreaded application and the thread calling getTest is a working thread, not event-driven thread.
On the other hand, if your application just wants to do something with the received response, there is imho no reason why you need a blocking method in the first place. Just perform your actions in the slot directly - just like it is in the Qt documentation.