Multithreading advice - c++

I am developing an application, the main goal is to grab images from a frame grabber, do some processing and then show images on a GUI.
The frame grabber is connected to the PCIe. And I'm using the frame grabber SDK.
The image stream is pretty slow 10 to 100 images/s
I am here to have some advice about my code and how to optimize it.
First, there is my run() function from a class inherited from Qthread
I grab an image and put it on a buffer queuecv:: Mat>.
void ImageIn::run(){
_cam->allocMemory();
_cam->startAquisition();
_runningThread = true;
while(_runningThread)
{
Mat image(_cam.getSizeX(), _cam.getSizeY(), CV_16U, _cam->getImageDMA0());
_ctrl->getMutexIn()->lock(); // Lock BufferIn
_ctrl->getBufferIn()->push(image); // store Image in BufferIn
_ctrl->getMutexIn()->unlock(); // Unlock bufferIn
}
}
Images are stored in a buffer and then the processing thread do some work...
void ImageProcessing::run(){
while(_runningThread){
if (_ctrl->getMutexIn()->tryLock()){
while(!_ctrl->getBufferIn()->empty()){
_ctrl->getBufferIn()->front().convertTo(tempConvert, CV_32F);
_bufferLocalIn.push(tempConvert);
_ctrl->getBufferIn()->pop();
}
_ctrl->getMutexIn()->unlock();
}
// Do some processing and put image and a buffer for GUI
}
}
So, I have some questions:
- The thread 1 gets images thanks to a blocking function, so the CPU consumption is low, but the thread 2 run continuously and consumes a lot of CPU reassess what can I do for fixing that?
- is it the right way to code that?
So i tried that :
QThread* thread = new QThread;
ImageWriter* worker = new ImageWriter();
worker->moveToThread(thread);
QTimer* timer = new QTimer();
int msec = 100;
timer->setInterval(msec);
QObject::connect(thread, SIGNAL(started()), worker, SLOT(process()));
QObject::connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
QObject::connect(timer, SIGNAL(timeout()), thread, SLOT(start()));
timer->start();
is it ok ?

As Qt is an event driven framework, each thread has an event queue which receives events and sends them to various objects to receive them.
If any section of code in a thread has essentially a while(1) loop, then event propagation cannot occur and this is what you're doing in both threads with
while(_runningThread)
Starving the event processing in an infinite loop is the cause of excessive CPU consumption.
It is possible to use to get Qt to process events with a call to QApplication::processEvents within the infinite loops, but this is not ideal.
A better method would be to time-slice the processing with QTimer and allow the event propagation to occur naturally. This would require deciding how long processing could occur, before saving the processing state and then returning back to the event loop. A tick of the timer would call your processing function which can then restore state and resume.
This method will be easier if you create a processing class derived from QObject which you move to a QThread, rather than inheriting directly from QThread itself. There's a great article on How to Really Truly Use QThread which can be used as a template on how to do this.
Finally, consider that you can have more than one QThread, as well as more than one QObject running on a QThread. As a general rule, you will not benefit if the number of threads exceeds the number of processor cores available.
If you know the target machine is a quad core, you can create 3 extra QThreads (4 in total, including main), create multiple processing objects and move them to different threads to provide optimal processing.

Related

How to properly using infinite loop in Qt GUI?

I am new to and learning the Qt GUI framework.
I have an ultrasonic sensor wired up to the Raspberry Pi, to measure water level. If I were coding in C, I would have used a while(1) loop to constantly read the sensor input. But when I put while(1) inside MainWindow.cpp, the window cannot be displayed. However, using qDebug() I can still print out the sensor value, which means my while(1) still running but the main window won't appear. I found out in this answer that because of while(1),
MainWindow ctor never returns, so w.show() is never called and a.exec() (main message loop) is never executed.
To solve this, I use QTimer instead of a loop: connect the timeout() SIGNAL to a SLOT which is a function to read the sensor value one-time:
waterLevelTimer = new QTimer(this);
connect(waterLevelTimer, SIGNAL(timeout()), this, SLOT(getWaterLevel()));
waterLevelTimer->start(100); // "loop" once every 100 millisecond
With this method, I can read the sensor value with the fastest interval is 1 millisecond and the GUI still displayed fine.
But should I use QTimer to mimic a while(1) loop? Is there a better way to have an infinite loop to read GPIOs while still being able to use GUI for other work?
The main thread where the GUI of Qt runs never should be blocked by long-lasting operations like an infinite while-loop, because otherwise you would block the event system and nothing will work anymore.
Instead you usually create a worker thread in parallel (see QThread) where you do your loop in the run function of the thread. Maybe also use such timer as you suggest, which works if the executed code is faster than the timer duration.
QThread *thread = QThread::create([]{
while(1)
checkSomething();
});
thread->start();

The canonical way to use a QTimer in a separate thread

I am tying to create a worker thread that will update a QTWidget at 1 second intervals (think of it as a digital clock or a progress bar updater might be a better analogy given the application).
My application is avionics specific that computes flight tracking info over a flight path and updates a map or some other QT widget regularly during the progress of the flight at 1 sec intervals (I suppose you could think of it as a sort of progress bar - where the progress bar could be replaced by a map or table widget in my case). The thread will probably take about 10-20 seconds to compute the entire flight data - (however it will have its first results available almost immediately) - these results need to be sent at 1 second intervals to the GUI to update the position of an aircraft on a map.
There is a lot of confusion about the right and wrong way to incorporate a timer that updates a worker thread. The best source of knowledge I found was a QtCon talk entitied Multithreading with Qt - Giuseppe D’Angelo - it seems that the preferred method is to have a worker QObject that does not subclass a QThread and that has the timer running in its own event handler - but there is a lot of confusion about moving the worker thread to another thread that I don't understand very well and I am looking for some canonical advice on how to do this right. Doing so in a Lambda would be ideal as I could keep the logic and threading relatively isolated which would be ideal.
I am looking to see if someone could point me in the direction of a similar example (especially if it uses modern Lambdas). I am currently using QT 5.11.2.
My worker object (which contains the QTimer is as follows):
class SimulatedFlightWorker : public QObject
{
Q_OBJECT
public:
explicit SimulatedFlightWorker()
: mpMMRFlightData{}
{}
public slots:
// worker thread slot that computes the mpMMRFlightData
void importSimulatedFlight(
const QString& fileName,
const int aPlaybackSpeed);
void updateGUI(int secondsElapsed);
signals:
// every second during the flight we need to send a new MMR
// record to the GUI - to display on a spreadsheet or google map
void updateFlightData(const MMRTimedRecord& rMMRRecord);
// this is effectively when the worker thread is done
void flightCompleted();
private:
QTimer mTimer;
// the
std::unique_ptr<MMRFlightData> mpMMRFlightData;
};
This is the code where I setup the signals and slots (not working yet)
// Experimental worker model adapted from YouTube tutorial
// by Giuseppe di Angelo https://www.youtube.com/watch?v=BgqT6SIeRn4
auto thread = new QThread;
auto worker = new SimulatedFlightWorker;
connect(thread, &QThread::started, worker, &SimulatedFlightWorker::importSimulatedFlight);
connect(worker, &SimulatedFlightWorker::flightCompleted, thread, &QThread::quit);
connect(thread, &QThread::finished, worker, &SimulatedFlightWorker::deleteLater);
worker->moveToThread(thread);
thread->start();
It’s really simple:
Your calculations are done in a QObject-derived class
Updates are issued via a signal in that object.
Calculations are done in small chunks that take 10-20ms.
The calcualtions are triggered from a zero-duration timer – it’s not a timer, but a way of detecting event loop idle state in a thread.
The updates are triggered from a 1-second timer.
This class can be run on any thread — it will even work on the GUI thread, but will make it a bit less responsive (but not at all unresponsive).
You’d normally instantiate the class, start computations, and move it to a dedicated thread.

Qt GUI application stops realtime process when interacting with gui

I have a Qt GUI application that is doing some important real time work which must not be interrupted at all costs (Forwarding some incoming Serial traffic over LAN). At the moment the application is running flawless when there is no interaction with the GUI, but as soon as you click on a button or drag the form around, it seems like the forwarding is stopped for the time the click is being processed. Forwarding is done in a QTimer loop which I already put on a different thread than the GUI thread, but no change in the outcome.
Here's some parts of the code:
class MainWindow : public QMainWindow
{
QSerialPort serialReceiver; // This is the serial object
QTcpSocket *clientConnection;
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
// Some Initializations ...
QThread* timerthread = new QThread(this); // This is the thread that is supposed to do the forwarding
QTimer *timer = new QTimer(0);
timer->setInterval(25);
timer->moveToThread(timerthread);
connect(timer ,SIGNAL(timeout()),this,SLOT(readserialData())); // Run readserialData() each 25ms
timer->connect(timerthread, SIGNAL(started()), SLOT(start()));
timerthread->start();
}
void MainWindow::readserialData()
{
if(serialReceiver.isOpen() )
{
qint64 available = serialReceiver.bytesAvailable();
if(available > 0) // Read the serial if any data is available
{
QByteArray serialReceivedData = serialReceiver.readAll(); // This line would not be executed when there is an interaction with the GUI
if(isClientConnet)
{
int writedataNum = clientConnection->write(serialReceivedData);
}
}
}
}
As I said earlier, this code is running fine under idle circumstances without any data loss. Am I doing something wrong?
It is a good idea to run you important real time work in another thread. The GUI thread or main should do drawing and the other one should do processing.
Qt's documentation about GUI thread says:
GUI Thread and Worker Thread
As mentioned, each program has one thread when it is started. This thread is called the "main thread" (also known as the "GUI thread" in Qt applications). The Qt GUI must run in this thread. All widgets and several related classes, for example QPixmap, don't work in secondary threads. A secondary thread is commonly referred to as a "worker thread" because it is used to offload processing work from the main thread.
And also when to use multithreading
Using Threads
There are basically two use cases for threads:
Make processing faster by making use of multicore processors.
Keep the GUI thread or other time critical threads responsive by offloading long lasting processing or blocking calls to other threads.
In your case running the realtime processing in separate thread will fix UI lagging issues and also will fix realtimeness issue.
I suggest you to read Threading basics from Qt's doc.
Threading basics

Using sleep_for() in Qt application

In my application I want to display some image with this code
myImage = scene->addPixmap(image);
myImage->setOffset(x, y);
Then I want to sleep for some seconds:
std::this_thread::sleep_for(std::chrono::seconds(2));
and then display another image. But this code waits for 2 seconds at first and then displays both images at once. How can I make the program wait between displaying those two images?
Use QTimer::singleShot() and connect it to a slot that updates the picture:
class MyObject : public AQObjectInheritingClass
{
Q_OBJECT
...
public Q_SLOTS:
void changeImage()
{
//change image here
}
And in instead of sleep_for():
QTimer::singleShot(2000, &instanceOfMyObject, SLOT("changeImage()");
Two seconds later, changeImage() will be invoked.
You cannot sleep in event based application (GUI applications are event-based). Event based applications have main loop, that has to be running to process events, and update its state. Calling sleep_for stops that main loop, so your app doesn't process events so it doesn't react to input and doesn't repaint itself. That's why all drawing if deferred fot two seconds then flushed at once.
As an alternative, you should use timers, such as QTimer
there is Qt-specific non-blocking way to pause thread with QEventLoop:
QEventLoop loop;
QTimer::singleShot(1000,&loop,SLOT(quit()));
loop.exec();
While loop is being executed, all other events for this thread are processed.

How do I start polling with mutex locked thread in QT?

I am using Ubuntu 12.04 with Qt version 4.8.3.
In Qt main window I manage to open my devices and this part of the code is working.
Now after I open devices I need to wait if a card is present. It means I have to use polling to get the data from card. But the polling must be infinite loop. Polling for card arrival and removal.
Example poll for card arrival every 20ms and when a card is detected I need to switch poll for card removal every 20 ms. So when a card arrival or removal is detected, my app signals Qt event such that another Qt thread can now proceed to read/write the card.
I read about QThread, mutex locked so on and I am bit confused.
I have a main window plus a worker class. In my mainwindow I code as;
// Open a reader (from my SDK)
cReader.open
//If the reader is open use;
thread = new QThread();
worker = new Worker();
worker->moveToThread(thread);
connect(worker,SIGNAL(??????),SLOT(?????);
connect(worker,SIGNAL(?????),SLOT(?????);
.........
First I must use connect for SIGNAL/SLOT and start the card arrival/removal polling. Than if any card detected I have signal to another thread to read from card or write into the card.
So I don’t know where to start or how to call signal/slot? I need help to fill the ?????? above SIGNAL/SLOT.
Edited: I also need mutex lock shared by the polling thread and the card handiling thread. This is because a card poll command will invalidate my mifare session if opened.
Any help please,
Kind Regards,
Using QMutex for protection an object, on the example of your cReader:
// class member
QMutex m_mutex;
//...
QByteArray MyClass::safeReadSomeData()
{
m_mutex.lock();
QByteArray result = cReader.read();
m_mutex.unlock();
return result;
}
See also QMutexLocker, QReadWriteLock.
Common and usual way for communication and parameters exchange between threads is using signals & slots. Example:
thread = new QThread();
worker = new Worker();
worker->moveToThread(thread);
connect( thread, SIGNAL(started()), worker, SLOT(startMyWork()) );
connect( worker, SIGNAL(sigCardDetected()), someOtherObject, SLOT(onCardDetected()) );
thread->start();
//...
Useful article from official documentation: Threads and QObjects
Also I think this answer about QThread will be useful for you: https://stackoverflow.com/a/35056527/4149835
p.s. Are you sure that you need to use two different additional threads for detecting and reading/writing?
It is not thread-safe (unless one QObject accesses data in another QObject and both belong to the same thread).
In terms of usage of mutexes the QMutexLocker is your friend and I advise you to use it instead of manually handling the locking/unlocking.
If you re-read your question you will notice that you heavily use intervals. And how do we handle intervals? Using QTimer. Here is my suggestion:
Create a QTimer along with the worker QObject
Set the interval of the timer to 20ms or whatever interval you want for it to tigger an event; a timer with interval set to 0 means that an event will be triggered by it as soon as possible
Connect the timer to the slot of the worker that does the work (check if card is removed etc.)
Connect the object's slots/signals to the signals/slots of your UI (using QMutexLocker will enable you to secure the access on the internal data of both) or another QObject (in the same or a different thread where the worker is residing)
Move both the timer and worker to a QThread and start the thread
The timer will start triggering a check for your card every X milliseconds. The worker will then receive that signal from the timer (here no mutex is required since both the timer and the worker are with the same thread-affinity). Things will change internally for the worker and then it will emit a signal to another QObject or the UI itself. At this point the mutexes come into play unless you are accessing another instance of a QObject in the same thread where your worker is.
You can add as many threads as you like by doing so. I have a UI that has 6 threads running in the background accessing both the UI and each other without any problem using timers.
EDIT:
I have started working on a small demo using QTimer, QThread and QObject. Application is incomplete/buggy but you can see how QTimer works.