Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multithreading advice

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 ?

like image 712
Hicham d'Azimani Avatar asked Oct 31 '22 14:10

Hicham d'Azimani


1 Answers

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.

like image 127
TheDarkKnight Avatar answered Nov 15 '22 04:11

TheDarkKnight