Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multithreaded Qt Application does not stop when quit

I'm writing a simple Qt program to capture video feed from camera (using OpenCV). I'm using a QThread object that loops, capturing images and feeding them to the MainWindow object. This is working as it should.

The problem is that when I close, the application (i.e. pressing the "X") the camera capturing thread stops and the gui disappears. But the program is still running in the background. I also get a warning in the application output saying :

QThread: Destroyed while thread is still running.

How can I stop the application completely when quitting it?

main.cpp

#include <QApplication>
#include "application.h"

using namespace cv;

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    Application app;
    app.init();

    return a.exec();
}

application.h

#include "mainwindow.h"
#include "camerathread.h"
#include "mathandler.h"
#include "tools.h"
#include "opencv2/core/core.hpp"

#ifndef APPLICATION
#define APPLICATION

class Application : public MatHandler{
    MainWindow w;
    CameraThread ct;
public:
    Application() {
        w.setFixedSize(800,600);
    }

    void init() {
        ct.setMatHandler(this);
        ct.start();
        w.show();
    }

    void handleMat(cv::Mat mat) {
        QImage qImage = toQImage(mat);
        w.setImage(qImage);
    }
};

#endif // APPLICATION

camerathread

#include <QThread>
#include "mathandler.h"
#include "opencv2/highgui/highgui.hpp"

#ifndef CAMERATHREAD
#define CAMERATHREAD

class CameraThread : public QThread {
    MatHandler *matHandler;
public:
    ~CameraThread() {
    }

    void setMatHandler(MatHandler *h) {
        matHandler = h;
    }

private: void run() {
        cv::VideoCapture vc(0);

        if (vc.isOpened()) {
            for(;;) {
                cv::Mat img;
                vc >> img;
                matHandler->handleMat(img);
            }
        }
    }
};

#endif // CAMERATHREAD

The program consists of more code than this, but I only included the code I think is relevant for the question. I'll post the rest if necessary.

like image 255
birgersp Avatar asked Oct 19 '22 18:10

birgersp


1 Answers

There are some major problems with your code. First of all in your run function the unending for loop will cause your thread to never stop unless you manage thread termination by your self like :

while(!finishThread)
{
   cv::Mat img;
   vc >> img;
   matHandler->handleMat(img);
}

You should set finishThread to true when the application is going to close. Just provide a slot in which you set the value for finishThread. When you want to terminate the thread emit a signal that is connected to that slot with a true value. After that wait for the thread to finish properly for some seconds and force it to terminate if it did not finish :

emit setThreadFinished(true); //Tell the thread to finish
if(!ct->wait(3000)) //Wait until it actually has terminated (max. 3 sec)
{
    ct->terminate(); //Thread didn't exit in time, probably deadlocked, terminate it!
    ct->wait(); //We have to wait again here!
}

Also you should not directly call handleMat function from an other thread. It may cause your application crash or lead to undefined behaviour. For that use signal/slot mechanism. Connect a signal from your thread to that slot and emit the signal along the argument each time you want to call it.

An other point is that you are better to derive your class from QObject and use moveToThread. You can do this in the constructor of your class:

th = new QThread();

this->setParent(0);
this->moveToThread(th);

QObject::connect(th,SIGNAL(started()),this,SLOT(OnStarted()));
QObject::connect(th,SIGNAL(finished()),this,SLOT(OnFinished()));

th->start();

Your initialization and termination tasks should be done in OnStarted() and OnFinished() slots respectively. You can have a worker function in which you run the repetitive operation.

Also in the destructor of your Application class quit the thread in some way like the one stated.

like image 54
Nejat Avatar answered Oct 22 '22 11:10

Nejat