在退出应用程序上安全退出Qt线程

时间:2015-04-03 13:33:32

标签: c++ multithreading qt

我正在尝试为Scanner类创建一个线程,该类处理此特定类的所有事件,从而释放GUI线程。我的GUI上有一个退出按钮,只需调用qApp-> quit()退出应用程序,但我不知道如何处理我的Scanner类中的线程。退出应用程序时,我在调试日志中看到以下错误。

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

在Scanner.cpp中(省略其他功能)

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();
}

在主Window.cpp(省略其他功能)

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();
}

有关如何安全退出的任何指针在多线程应用程序中退出应用程序。

3 个答案:

答案 0 :(得分:4)

您需要让Scanner类知道应用程序正在退出。

将以下行添加到MainWindow

的构造函数中
connect(qApp, SIGNAL(aboutToQuit()), &m_scanner, SLOT(deleteLater()));

更新:

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

不应该在Scanner

的构造函数中

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

不应该在Scanner

的析构函数中

事实上,m_thread不应该以任何方式成为Scanner的一部分。 QThread类不代表线程,它是一个线程管理器,应该从创建它的线程中拥有和控制。

在Qt中有许多使用线程的方法,很多都没有很好地记录。如果你想使用

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

使用线程的方式,然后m_thread应该是MainWindow类的成员,并且这些函数调用应该在它的构造函数中进行。

答案 1 :(得分:0)

首先,您应该将QThread移出Scanner类。 QThread管理一个线程,因此您无法调用与该线程本身内部的线程管理相关的函数。这就是你获得关于线程等待消息的消息的原因。

你应该有类似的东西:

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

然后,在你的quit函数中,按照你想要的方式,在退出之前等待线程(更好)或终止它(更糟糕),或者权衡,例如:

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

答案 2 :(得分:0)

感谢您澄清以及上面发布的解决方案。这是我根据以前发布的内容做的。

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();

}

在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;
};

在MainWindow.cpp中(省略其他功能)

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();
}

这对我来说似乎很好。如果您发现任何错误,请更正,并感谢您的帮助。