How to use threads in Qt GUI - c++

I have an application that continuously reads an image from a camera and displays this to a user. The user can adjust different sliders such as exposure and threshold to modify the image in real-time. I also do a bunch of calculations on this image afterwards which sometimes makes the GUI unresponsive, so I decided to use threads to divide the workload.
However, I can't get it to work properly, sometimes I get segmentation faults and a bunch of "assertion ` GLib-GObject-CRITICAL **: g_object_unref: assertion 'G_IS_OBJECT (object)' failed" warnings when the slider values are changed or if I try to save the image (save button in my GUI), and the GUI sometimes stops updating the image or freezes so you can't move the sliders or push any buttons.
What I tried to do was to use the standard std::thread in C++, and connect it to the start button through a slot.
QObject::connect(btnStart, SIGNAL(clicked()), this, SLOT(RunStartThread()));
void MainMenu::RunStartThread(){
std::thread t1;
t1= std::thread(&MainMenu::Start,this);
t1.detach();
}
void MainMenu::Start() {
run = true;
window->mngr->ReadCalibration();
window->mngr->InitializeCameras();
while (run) {
window->mngr->CaptureImage();
window->mngr->ProcessImages();
UpdateLabels();
}
window->mngr->Stop();
}
When the user changes the slider values they change variables in my manager (mngr above) that captureImage and ProcessImages uses. I tried using a std::mutex lock/unlock when a variable was to be accessed, but it did not change anything. I've tried to find examples of how to do this online, but have yet to find something that has a continuous while-loop.
I'm a newbie when it comes to threads, so just tell me if I'm approaching this in the wrong way.

First for all for inter thread communication use singnals and slots. By default Qt connections do nice thread hopping between threads which lets to avoid complex synchronization.
Secondly you have three ways of using threads: QThread, QRunnable, QtConcurrent::Run (my favorite, since requires minimum amount of code).
In case QThread please do not subclass it! It is common design mistake.
Example:
SomeClass::~SomeClass()
{
SignalStop();
future.result();
}
void SomeClass::RunStartThread(){
future = QtConcurrent::run(this, &SomeClass::DoOnThread);
}
void SomeClass::DoOnThread()
{
while (ShouldContinueToRun()) {
QImage im1 = CaptureImage();
emit ImageCaptured(im1);
QImage im2 = ProcessImages(im1);
emit ImageProcessed(im2);
}
emit JobCompleted();
}
Please note that QObject::connect has last argument which defines how invocation of slot is performed if different thread is involved. See documentation of enumeration used for this argument.
So by default Qt detects if thread hopping is needed or not. Reading carefully about QObject::moveToThread should also help to understand the problem (note you can't move object to different thread if it has a parent).

Related

QDialog box showing blank when MainWindow thread is busy

I am working on a Qt-C++ based front-end app for a Raspberry Pi powered robot. I am using Qt version 5.9 along with libraries QSerialPort and Pigpio. In my app, when I give the run command for a command sequence to the robot, my Raspberry Pi starts a serial communication with a microcontroller in which it sends some message and then waits to receive a response. This sending and waiting causes the Mainwindow thread to freeze up. I am trying to build in a emergency stop functionality, which would stop the command execution in the middle of the run process.
Towards that effort, I tried to push my serial communication part to a separate thread(QThread). It didn't work out. Now I am trying to build the emergency stop part into a QDialog box that opens up when I give the run command, which contains a emergency stop QPushbutton. The Dialog box is being run in non-modal form. But in my current code, when I give the run command, a dialog box does open up, but the dialog box is completely blank and then closes up when the run command ends(which is intentional). I'll share some screenshots of the appearance.
Can you suggest where I might be going wrong? Or is there a better approach to this issue? Any criticism and suggestions are welcome!
Thanks!
One shouldn't block the main thread in the Qt. Everytime you call the blocking function, your GUI freezes, as well as Dialog boxes.
One solution is to use signal/slots. They blend really well into Qt. But doing a complicated request/response logic would require a huge state machine usually prone to errors.
Sometimes it is better to leave this code blocking, create a plain chain of request/response code, and put it in another non-GUI thread. Then use the signal to notify the main thread about the job result.
In order to stop the execution it is possible to use an atomic and check it between blocking steps. The biggest time delay before exiting the working function is the biggest delay of the single blocking function. You should carefully tune the timeouts. Or you can write your own function, which emulates timeout and a stop condition. It should check if incoming data is available in an infinite loop and check fro stop condition on each iteration, which must be a timeout AND a stop condition variable.
// pseudocode here
while (true) {
if (stopCondition) return; // check for emergency condition
it (currentTime - startTime > timeout) return;
if (serial->dataReady()) break;
}
auto data = serial->getData();
If a step can block forever, then this method can't be used.
There is an example with QtConcurrent framework, which demonstrates the use of QFuture and the work of a function in a separate thread without blocking the main thread. You can put all your communication logic inside it.
The code is example only!
#ifndef WORKERCLASS_H
#define WORKERCLASS_H
#include <QObject>
#include <QtConcurrent/QtConcurrent>
#include <QFuture>
class WorkerClass : public QObject
{
Q_OBJECT
public:
explicit WorkerClass(QObject *parent = nullptr) : QObject(parent) {
connect(&futureWatcher, &QFutureWatcher<void>::finished, [this] () {
emit workFinsihed();
});
}
void startWork(int value) {
atomic = 0;
future = QtConcurrent::run(this, &WorkerClass::workFunction, value);
futureWatcher.setFuture(future);
}
void stopWork() {
atomic = 1;
}
private:
QFuture<void> future;
QFutureWatcher<void> futureWatcher;
void workFunction(int value) {
for (int i = 0; i < value; ++i) {
if (atomic) return;
}
return;
};
QAtomicInt atomic{0};
signals:
void workFinsihed();
};
#endif // WORKERCLASS_H

Qt - How to create a QFuture from a thread

I am currently working on an editor program; there's a feature I need to write, which requires loading several files in a row using the project's asynchronous file API, then performing some more computations once those files are loaded.
In another language, this would probably be implemented with an async/await workflow, eg:
let firstFile = await FileAPI.loadFile("Foo.xxx", ...);
let otherFile = await FileAPI.loadFile("Bar/Foobar.xxx", ...);
The Qt equivalent to this code would be to spawn a new thread using QtConcurrent::run, returning a QFuture, and waiting for that future to yield a result.
However, in the project I work on, the file-opening API runs on a single worker thread, which means I can't use QtConcurrent::run. This is an established, non-negotiable part of the codebase. Eg the constructor of the file API looks like:
FileApiWorker* worker = new FileApiWorker();
m_workerThread = new QThread();
worker->moveToThread( m_workerThread );
// Input signals
connect( this, &FileApi::loadFile, worker, &FileApiWorker::loadFile);
connect( this, &FileApi::loadData, worker, &FileApiWorker::loadData);
connect( this, &FileApi::loadDir, worker, &FileApiWorker::loadDir);
Which means my only way of accessing filesystem data is to call a method which emits a signal, which starts the computation on another thread, which eventually emits its own signal at the end to pass on the loaded data.
This is extremely impractical for the use case above, because instead of saying "do thing, load data, wait, keep doing things", I essentially need to say "do thing, load data (with call back 'keep doing things')" and "keep doing things" in another function, which introduces all sorts of brittleness in the code. (and, well, you know, that's exactly the sort of workflow we invented futures for)
Is there some way I could create a QFuture, or some future-equivalent object (that can be awaited inside a method) from the loadFile method, given that loadFile always runs on the same worker thread and I am not allowed to create new threads?
The simplest way to create a QFuture in Qt is with the undocumented QFutureInterface class.
Example code:
Q_DECLARE_METATYPE( QFutureInterface<FileData> );
// ...
qRegisterMetaType<QFutureInterface<FileData>>();
FileApiWorker* worker = new FileApiWorker();
connect( this, &FileApi::loadFile_signal, worker, &FileApiWorker::loadFile_signal);
// ...
QFuture<FileData> FileApi::loadFile()
{
QFutureInterface<FileData> futureInterface;
// IMPORTANT: This line is necessary to be able to wait for the future.
futureInterface.reportStarted();
emit loadFile_signal(futureInterface);
return futureInterface.future();
}
FileApiWorker::loadFile_signal(QFutureInterface<FileData>& futureInterface)
{
// Do some things
// ...
futureInterface.reportResult(...);
// IMPORTANT: Without this line, future.waitForFinished() never returns.
futureInterface.reportFinished();
}
Some factors to account for:
The above code uses Q_DECLARE_METATYPE; which is necessary to be able to pass QFutureInterface through a cross-threads signal. To be precise, the connect line will fail to compile if Q_DECLARE_METATYPE isn't included; and the emit loadFile_signal line will fail at runtime if qRegisterMetaType isn't called. See the Qt documentation on metatypes for details.
You can propagate errors, in such a way that calling loadFile().waitForFinished() throws on error. To achieve this, you need to create a special-purpose class inheriting QException, then call:
futureInterface.reportException( MyException(...) );
futureInterface.reportFinished();
in your error path.
QException is essentially a wrapper for actual exceptions that need to be transferred between threads. See the documentation for details.
While QFutureInterface is stable, and mostly has the same API as QFuture and QFutureWatcher, it's still an undocumented feature, which may surprise contributors coming across it in a shared codebase. The class can be counter-intuitive, and fail silently if you don't respect the points above (which I had to learn through trial and error). This must be stressed in the comments of any shared code using QFutureInterface. The class's source code can be found here.
IMO, it is strange not to use ready-to-use solutions (AsyncFuture) and try to rewrite from scratch.
But I can suggest my own "wheel": lambda as a slot.
void FileApi::awaitLoadFile()
{
qDebug() << "\"await\" thread is" << thread();
emit loadFile("Foo.xxx");
static bool once = connect(m_worker, &FileApiWorker::loadFileDone, this, // there is possible to avoid the third "this" parameter, but it is important to specify the lifetime of the connection and the receiver context while using lambdas
[=](QByteArray result)
{
qDebug() << "\"comeback-in-place\" thread is" << thread(); // will be the same as "await" thread was
// do what you need with your result
},
Qt::QueuedConnection // do not forget
);
qDebug() << "here is an immediate return from the \"await\" slot";
}
Useful arcticle New Signal Slot Syntax - Qt Wiki

Corrupt QImage after a signal/slot call between two different threads

I am sending a QImage via a signal/slot mechanism, between two threads (a background DB thread and a GUI thread). The GUI slot receives a corrupt image (some pixels are randomly corrupt). I have done this already, and never had any issue. What could be wrong?
The programm is too complex to be included here, but here is some relevant information:
The sending thread (DB) is a regular QThread, with an event loop, running a DataBaseInterface QObject class which was moved to this thread
The signal/slot connection was done after the moveToThread, so each object is in its final thread. This means that explicitely using QueuedConnection makes no difference as this is already the case.
The QImage is not sent directly in the signal/slot parameters, but within a struct which contains other stuff (three QVectors). This struct was registered using:
qRegisterMetaType<MyStruct>("MyStruct");
The QImage was not created using an external buffer, but with the (width, height, Format) constructor. So the image buffer is maintained internally and thus implicitely shared
If I save the image to disk in the DB thread just after emitting the signal, it is good. If I save it just at the beginning of the slot, it is corrupt.
Any idea?
Thanks!
Ok, o that the image is not corrupted you should ensure the following:each data containing the structure that are sending must have copy constructor, avoids sending data pointer and if you do it sure that these reside in memory heap, the connection type for these cases is Qt::QueuedConnection, the label on establish the image that you think should be configured as follows:
label->setBackgroundRole(QPalette::Base);
label->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
label->setScaledContents(true);
the slot where the image or comes your structure should look like this, in my case with opencv and QT is:
void interfaz::actImagenFromVideo(cv::Mat myImage)
{
QImage image(myImage.data,myImage.cols, myImage.rows, myImage.step, QImage::Format_RGB888 );
label->setPixmap(QPixmap::fromImage(image.rgbSwapped()));
}
he run function of your QThread should look something like:
void THREAD::run()
{
while(true){
{
QMutexLocker locker(&mutex);
if (stopped) {
stopped = false;
break;
}
}
cap>>videoIn;
emit image_ready(videoIn.clone()); //the use of cv::Mat::clone() is very important in openCV
}
}

Qt/C++: Checkable button and infinite loop

I'm coding a Qt Gui and I'm trying to implement a new feature, I now the precise result I want to arrive at but not how to code it.
I'm trying to add a checkable button that when checked would run a function that would only stop when the button is unchecked, but every second a PaintArea I have on the window would be updated (letting me see how the multiple executions of my function are changing my data). It seem that I'll need to use some QThread objects, but just the part dealing with the button is already counter intuitive to me, I've been trying to play with the autoRepeatDelay and autoRepeatInterval without getting my hand on what they do and how they could be useful to me.
I guess that what I'm trying to code is not really original, would have an idea of the steps to implement it, or an example of a code?
Edit:
According to the first answers (thank you for them by the way) my question may not be clear. Putting on the side the thread thing, I'd like to implement an infinite loop that only starts when a pressbutton goes to pressed position (it's a checkable button) and stops only when leaving it. The first version I tried to do (with a while(button->isChecked() loop) would completely freeze as the application would be running the loop, the gui would freeze and the button couldn't be turned off (hence the idea of running it in a separate thread). Voila! I hope it's a clearer formulation. Thank you in advance.
Here's a simple skeleton of something that might work. Without knowing your exact requirements, it may or may not be right for your problem. Hopefully it will give you a few hints that do actually help.
void Ui::buttonPressedSlot(bool checked){
if (checked){
Processor *processor = new Processor;
connect(this, SIGNAL(abortCalculations()), processor, SLOT(abort()), Qt::QueuedConnection);
connect(processor, SIGNAL(updateNeeded()), this, SLOT(updateGui()), Qt::QueuedConnection);
QThreadPool::globalInstance()->start(processor);
} else {
emit abortCalculations(); // this is a signal in your UI class
}
}
You can then use the following for your calculations.
class Processor : public QObject, public QRunnable{ // QObject must always be first in multiple inheritance
Q_OBJECT
public:
~Processor();
void run();
public slots:
void abort();
void doCalculations();
signals:
void updateNeeded(); // connect this to the GUI to tell it to refresh
private:
QScopedPointer<QEventLoop> loop;
};
Processor::~Processor(){
abort();
}
void Processor::run() {
loop.reset(new QEventLoop);
QTimer timer;
connect(&timer, SIGNAL(timeout()), this, SLOT(doCalculations()));
timer.setInterval(1000);
timer.start();
loop->exec();
}
void Processor::abort(){
if (!loop.isNull()){
loop->quit();
}
}
void Processor::doCalculations(){
// do whatever needs to be done
emit updateNeeded();
}
I don't know if I really understand what you want to do, but I will try to answer.
First, you want a Button that send a start & stop info to control a thread. You can use a checkbox to begin. This check box send a signal when its state changes. Connect this signal to a slot that perform start thread and stop according to the boolean sent.
Second, in you thread you need to launch the events loop. After, set a timer that call you repaint after every timeout.
Hope it helped.
PS: take care of execution context with you thread and Qt's objects.

QtConcurrent mapped and progress report

I'm using QtConcurrent to do some heavy background image processing and I want to display the image while parts of it are being updated progressively.
Each line of the image is computed separately and is passed a functor.
To compute the full image I then have a sequence of item that I pass to QtConcurrent mapped and each line emits a signal when it is done computing
Here is the instantiation of the class Worker:
//living in the main(gui) thread !
Worker::Worker(VideoEngine* engine):_engine(engine){
_watcher = new QFutureWatcher<bool>;
_watcher->setPendingResultsLimit(200);
connect(_watcher, SIGNAL(resultReadyAt(int)), this, SLOT(onProgressUpdate(int)));
connect(_watcher, SIGNAL(finished()), engine, SLOT(engineLoop()));
}
Here is the slot to report progress:
void Worker::onProgressUpdate(int i){
if(i < (int)_rows.size() && i%10==0){
cout << " index = " << i << " y = "<< _rows[i] << endl;
_engine->checkAndDisplayProgress(_rows[i],i);
}
}
Now the usage:
void Worker::_computeTreeForFrame(.../*unrelevant args*/){
....
....
_watcher->setFuture(
QtConcurrent::mapped(_sequence,
boost::bind(&VideoEngine::metaEnginePerRow,_1,output)));
}
}
All the signals are emitted but the slot onProgressUpdate gets called only when Qtconcurrent::mapped is done with all the items in the sequence.
When executing it has a huge delay while the sequence is processing and then all slots are executed sequentially afterwards.
I have tried all types of signal/slots connection and none of them changed this behaviour.
Any clue ?
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EDIT after Shf suggestion
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
The call was made until now in the main(gui) thread.
I changed the call to :
_computeFrameWatcher->setFuture(QtConcurrent::run(_worker,&Worker::computeTreeForFrame));
Since _computeTreeForFrame is now executed in another thread, I changed the call to QtConcurrent::mapped to:
_watcher->setFuture(QtConcurrent::mapped(_sequence,
boost::bind(&VideoEngine::metaEnginePerRow,_1,output)));
_watcher->waitForFinished();
This results in exactly the same behaviour as before.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EDIT after Marek R suggestion
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ok so I made so tests and here is what I observed:
QtConcurrent::map :
Doesn't emit the signal resultReadyAt(int)
QtConcurrent::mapped
Emits resultReadyAt(int) only when finished
It doesn't matter if the call to the map function is done in a separate thread the same behaviour is encountered.
I also gave a try to the signal progressValueChanged(int) as the Qt progressDialog example suggests.
The signal progressValueChanged(int) gets emitted only for 2 lines in the image (the first and last).
This is really weird as in the Qt progress dialog example it is emitted smoothly.
I changed a bit the Qt example to launch the map function in another thread than the main thread and it still works well in that case.
The issue must arise from somewhere else.
Maybe the GUI event loop is doing something I don't expect ? I have no clue what.
I will now try QtConcurrent::mappedReduced and report with the results :-)
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EDIT after giving a try to QtConcurrent::mappedReduced
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
It doesn't work and calls the "reduce" function ONLY when the "map" function is done. In other words it does the same than the previous signal/slots mechanism.
I'm running low in possibilities now
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EDIT I'm back to a solution as close as the Qt progress dialog example
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Something must be wrong if I can't get the same behaviour than the Qt example.
Here's the code now:
//created in the main thread! (gui)
Worker::Worker(VideoEngine* engine):_engine(engine),_watcher(0){
_watcher = new QFutureWatcher<void>;
_watcher->setPendingResultsLimit(200);
connect(_watcher,SIGNAL(progressValueChanged(int)), _engine,
SLOT(onProgressUpdate(int)));
connect(_watcher, SIGNAL(finished()), engine, SLOT(engineLoop()));
}
//executed on the main thread
void Worker::computeTreeForFrame(...){
...
_watcher->setFuture(QtConcurrent::map(_sequence,boost::bind(metaEnginePerRow,_1,output)));
...
}
The call to computeTreeForFrame...
...
_worker->computeTreeForFrame();
...
This call is done in a slot .
It emits the signals for the line 0 and for the last line as told before but doesn't emits anything else.
Shouldn't this do EXACTLY what the Qt example does?
From task description it looks like you should use mappedReduced. Problem is that I don't see a good way to get partial results. One way to overcome this problem is to emit signal form reduce function.
It is possible that this thread may help.
It seems, that QtConcurrent::mapped does not put VideoEngine::metaEnginePerRow in another thread, judging by the documentation. If image is processed in the same thread as GUI, then your slots indeed will be executed after processing, no matter what type of connection you select, just as you've described.
The solution is to either run Worker::_computeTreeForFrame (as i understood, your main processing function) in another thread via QtConcurrent::run or to put your Worker object in another thread probably via QObject::moveToThread(). Then, the connection type you should use is Qt::QueuedConnection (or if you will put Worker in another thread before connection, you can connect even with Qt::AutoConnectionor Qt::UniqueConnection, caller and receiver will be in a different threads, so qt will automaticly chose QueuedConnection`)
EDIT:
I'm not sure, but your _watcher = new QFutureWatcher<bool>; is still created in the main thread and if you call
_watcher->setFuture(QtConcurrent::mapped(_sequence,
boost::bind(&VideoEngine::metaEnginePerRow,_1,output)));
_watcher->waitForFinished();
would _watcher set GUI thread to wait, in what it was created or thread, where this command is executed. If _watcher->setFuture(QtConcurrent::mapped(_sequence,
boost::bind(&VideoEngine::metaEnginePerRow,_1,output))); if the end of a function, is _watcher->waitForFinished(); needed at all? Qt will destroy thread right after it's execution and you set your processing function to run, why wait?
And _computeFrameWatcher should be of QFuture<void*> type.
EDIT2:
Ok, before i give up, i suggest you to test QObject::moveToThread:
before you call _worker->computeTreeForFrame(); , put it in another thread:
QThread *workerThread=new QThread();
_worker->moveToThread();
_worker->computeTreeForFrame();
/* connect _worker's finished signal with workerThread::quit and deleteLater slots */
and all connections within _worker should be DirectConnection and all connections between _worker and main (GUI) thread should be connected with QueuedConnection. Also it's probably good to create new thread in _worker constructor and move it to another thread immediately, this way you can destroy thread in _worker's destructor and don't worry about thread problem's in GUI thread