1

I'm trying to implement a multithreaded app that displays video using the OpenCV libraries (following the example given here).

I create two threads from the GUI thread that successfully terminate when the MainWindow is closed. However, the program still keeps on running (I have to use the stop button on the application output panel to close it down).

Here's my destructor for the MainWindow

MainWindow::~MainWindow()
{

captureThread.quit();
converterThread.quit();

if (captureThread.wait())
        qDebug() << "Capture Thread has exited successfully";

if (converterThread.wait())
        qDebug() << "Converter Thread has exited successfully";

delete ui;
}

The Application Output window returns the following output on both the Debug and Release builds

Capture Thread has exited successfully
Converter Thread has exited successfully

However, the application only quits in Debug mode.

From what I have gathered from a few google searches is that the application continues on running IF there is a thread that has not been properly terminated. Can that be the case here? If yes, then how may I know which other thread is also running in the program, so that I may terminate/quit it?

Using Qt 5.4 with MSVC 2013 and OpenCV 3.0 beta on Win 8.1

Edit I create my threads in MainWindow constructor

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);

// registers the type cv::Mat. After a type is registered, one can create/destroy objects at runtime
qRegisterMetaType<Mat>();

// Initializing class' instance
Capture* capture = new Capture;
Converter* converter = new Converter;

ui->labelFrame->setAttribute(Qt::WA_OpaquePaintEvent);
converter->setProcessAll(false);

capture->moveToThread(&captureThread);
converter->moveToThread(&converterThread);


converter->connect(capture, SIGNAL(matReady(Mat)), converter, SLOT(processFrame(Mat)));
this->connect(converter, SIGNAL(imageReady(QImage)), this, SLOT(setImage(QImage)));

// thread clean up
connect(&captureThread, SIGNAL(finished()), &captureThread, SLOT(deleteLater()));
connect(&converterThread, SIGNAL(finished()), &converterThread, SLOT(deleteLater()));

QObject::connect(capture, &Capture::started,
                 [](){ qDebug() << "capture started"; });

QMetaObject::invokeMethod(capture, "start");

captureThread.start();
converterThread.start();

Edit 2 : I modified my main.cpp to this

QApplication a(argc, argv);
MainWindow w;
w.show();

int ret;
ret = a.exec();
qDebug() << "QApplication.exec() returns " <<  ret;
return ret;

and I received the following message in the Application output window

QApplication.exec() returns  0
Capture Thread has exited successfully
Converter Thread has exited successfully

which is confusing, since the QApplication should quit after the threads have been stopped. so I moved the thread cleanup to the abouttoQuit() slot. The order of exiting has changed by this modification but the original problem remains. (The wrong order could be due to the implementation of the qDebug() function, but thats just me guessing)

PS I even added captureThread.terminate() and converterThread.terminate() in the destructor but still the results are the same.

Community
  • 1
  • 1
user3079474
  • 1,653
  • 2
  • 24
  • 37
  • Show your threads code and the code that creates them. – dtech Apr 19 '15 at 11:45
  • 1
    Can you show us the main method where your `MainWindow` is created and destroyed? – Simon Warta Apr 19 '15 at 12:23
  • @SimonWarta main method, from where MainWindow is called, is the standard Qt code. I haven't touched it at all – user3079474 Apr 19 '15 at 12:50
  • You need to debug your code. Without full code context it is impossible to help you with debugging. – Dmitry Sazonov Apr 20 '15 at 10:19
  • Is there something specific I should be looking for? I'm only asking since it exits successfully while I am debugging. PS it is my first multithreaded application so I might have missed something very obvious as well – user3079474 Apr 20 '15 at 10:21

2 Answers2

1

Problem

Ok so it turned out to be a memory leak. In the constructor of my MainWindow, I had declared and initialized two instances of converter * and capture * classes. However, when the constructor ended its scope, these pointers were never freed.

Solution

Free the memory in the CleanUp() function. (The CleanUp() function is connected to the aboutToQuit() slot of the application. To make the pointers accessible to the CleanUp() function, declare them as members of the MainWindow class.

user3079474
  • 1,653
  • 2
  • 24
  • 37
0
QMetaObject::invokeMethod(capture, "start");

Looks suspicious. Can you replace it with:

connect(&captureThread, &QThread::started, capture, &Capture::start);

Also, no need to do thread clean up, because they are members of MainWindow class and will be destroyed with it, remove those two lines:

connect(&captureThread, SIGNAL(finished()), &captureThread, SLOT(deleteLater()));
connect(&converterThread, SIGNAL(finished()), &converterThread, SLOT(deleteLater()));
psyched
  • 1,859
  • 1
  • 21
  • 28
  • I don't think so that `QMetaObject::invokeMethod(capture, "start");` is causing the problem as explained [here](http://stackoverflow.com/questions/13948337/why-using-qmetaobjectinvokemethod-when-executing-method-from-thread) – user3079474 Apr 20 '15 at 10:03