Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safely exit Qt thread on exit application

I am trying to create a thread for a Scanner class which handles all the events for this particular class, thereby freeing the GUI thread. I have an exit button on my GUI which simply calls qApp->quit() to exit the application, but I am not sure how to deal with the thread in my Scanner class. I am seeing the following errors in the debug log when the application is exited.

QThread::wait: Thread tried to wait on itself
QThread::wait: Thread tried to wait on itself
QThread: Destroyed while thread is still running

In Scanner.cpp (Omitted other functions)

Scanner::Scanner() :
{
    this->moveToThread(&m_thread);

    connect(&m_thread, &QThread::finished, this, &QObject::deleteLater);
    connect(this, SIGNAL(StartEnroll()), this, SLOT(StartEnrollment()));

    m_thread.start();
}

Scanner::~Scanner()
{
    m_thread.quit(); // Not sure if this is the correct
    m_thread.wait();
}

In main Window.cpp (Omitted other functions)

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this); 
    connect(ui->ExitButton, SIGNAL(released()), this, SLOT(Quit()));
    connect(&m_scanner, SIGNAL(FinishedEnroll(bool)), this, SLOT(EnrollDone(bool)));
}

void MainWindow::Quit()
{
    close();
    qApp->quit();
}

Any pointers on how to quit safely quit the application in a multi-threaded application.

like image 483
GMahan Avatar asked Mar 16 '23 13:03

GMahan


2 Answers

You need to let the Scanner class know that the application is exiting.

Add the following line to the constructor of MainWindow

connect(qApp, SIGNAL(aboutToQuit()), &m_scanner, SLOT(deleteLater()));

UPDATE:

connect(&m_thread, &QThread::finished, this, &QObject::deleteLater);

Should not be in the constructor of Scanner

and

m_thread.quit(); 
m_thread.wait();

should not be in the destructor of Scanner

In fact, m_thread should not be part of Scanner in any way. The QThread class does not represent a thread, it is a thread manager and should be owned and controlled from the thread where it was created.

There are a number of methods of using threads in Qt, many not documented very well. If you want to use the

workerObject->moveToThread(&thread);
thread.start();

way of using threads, then m_thread should be a member of MainWindow class and these function calls should be made in it's constructor.

like image 87
RobbieE Avatar answered Mar 19 '23 20:03

RobbieE


Thanks for clarifying and for the solutions posted above. Here is what I did based on what was posted before.

ScannerThread.h

#include <QThread>

class ScannerThread : public QThread
{

public:
    ScannerThread();
    ~ScannerThread();
};

ScannerThread.cpp

#include "scannerthread.h"

ScannerThread::ScannerThread()
{
    connect(this, &QThread::finished, this, &QObject::deleteLater);
}

ScannerThread::~ScannerThread()
{
    quit();
    wait();

}

In MainWindow.h

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
   void Quit();

private:
    Ui::MainWindow *ui;
    Scanner m_scanner;
    ScannerThread m_scannerThread;
};

In MainWindow.cpp (Omitting other functions)

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

    m_scanner.moveToThread(&m_scannerThread);
    m_scannerThread.start();

    connect(ui->ExitButton, SIGNAL(released()), this, SLOT(Quit()));
    connect(qApp, SIGNAL(aboutToQuit()), &m_scanner, SLOT(deleteLater()));

}

void MainWindow::Quit()
{
    close();
    qApp->quit();
}

This seemed to work fine for me. If you see any errors please correct, and thanks for helping with this.

like image 21
GMahan Avatar answered Mar 19 '23 19:03

GMahan