GMahan
GMahan

Reputation: 93

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.

Upvotes: 4

Views: 16468

Answers (3)

GMahan
GMahan

Reputation: 93

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.

Upvotes: 2

JBL
JBL

Reputation: 12907

First you should move your QThread out of the Scanner class. A QThread manages a thread, so you can't call functions that are related to the thread management inside that thread itself. That's the reason you're getting the message about the thread waiting on itself.

You should rather have something like that:

m_scanner.moveToThread(&m_thread);//make the thread a member of your window
m_thread.start();

Then, in your quit function, do as you want, either waiting on the thread (better) or terminating it (worse) before exiting, or a tradeoff, such as:

void MainWindow::Quit()
{
    close();
    //Wait maximum 1 second
    if(!m_thread.wait(1000) {
        m_thread.terminate();
    }
    qApp->quit();
}

Upvotes: 0

RobbieE
RobbieE

Reputation: 4360

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.

Upvotes: 5

Related Questions