Reputation: 129
I managed to implement a GUI Qt-based application in a worker C++ std::thread
like described here. Now I need both the main and worker threads to communicate.
My question is: how can I communicate messages (an array of floats) from my main thread to the worker thread so that I can update the GUI?
I have an application that performs real-time signal processing. My goal is to create a Qt GUI that can be plugged in into my application to visualize various signals without influencing the real-time aspect. I investigated different methods of how to accomplish this and concluded that this post describes quite closely what I need and provides a solution for it. However, there is no information on how the main and worker threads can communicate with each other.
I tried using the Futures/Promises approach described here to accomplish the inter-thread communication. Although I was able to get this example running, I couldn't integrate it into my project. The reason is that this approach relies on having a busy loop inside the worker thread that is constantly checking whether a new message has been sent by the main thread. However, in a Qt application, the program blocks once it enters the main event loop in a.exec()
. This prevents the busy loop check and hence causes the program to deadlock.
This is how I am spawning the GUI worker thread (based on this post).
#include <thread>
// Start the Qt realtime plot demo in a worker thread
int argc = 0;
char **argv = NULL;
std::thread t1
(
[&] {
QApplication application(argc, argv);
MainWindow mainWindow;
mainWindow.show();
return application.exec();
}
);
Upvotes: 3
Views: 1702
Reputation: 417
For signal processing you generally do not want the overhead of qts virtual calls. But that aside,
A good solution for thread to gui communication is found in: [email protected]:midjji/convenient_multithreaded_qt_gui.git
then its just e.g.
enter code here
run_in_gui_thread(new RunEventImpl([](){
QMainWindow* window=new QMainWindow();
window->show();
}));
callable from any thread, at any time, while taking care of setting things up for you in the bg.
Upvotes: 0
Reputation: 52397
You can use Qt's own methods to communicate between the threads. Each Qt object has a thread affinity. If you create your MainWindow
object in the separate GUI thread, it will be attached to that thread. If you use Qt signals and slots, and connect them with Qt::QueuedConnection
, the slot will be called in the object's thread, through that thread's main loop, regardless of where the signal came from.
Note that you can define signals in the MainWindow
class but invoke them from outside, as they are public. This means you do not need a separate sending object. In MainWindow
constructor (for example) you can connect its own signal to a slot or lambda method.
To be able to emit the MainWindow
signal, you can have a MainWindow
pointer set to nullptr outside the GUI thread, and set that pointer (through lambda capture) to the new object you create inside the GUI thread. Outside your thread, whenever you want to emit a signal, you can do sth. like if (mainWindow) mainWindow->signal(…)
. I assume you need a check anyways as your GUI is optional.
Two notes:
QMetaObject::invokeMethod
, it removes boilerplate, however signals can be connected through referencing the class method which is checked at compile time; The QMetaObject method uses string matching at runtime. Also with public signals, but protected slots, you can ensure that outside code doesn't accidentally call methods directly.connect(this, &MainWindow::signal, this, [this] {…});
will execute the lambda in the receiving thread, connect(this, &MainWindow::signal, [this] {…});
will not.Upvotes: 1