如何使用工作线程正确退出Qt应用程序



退出Qt应用程序的最佳实践是什么?我做这样的事情

int main(int argc, char *argv[])
{
    MyApplication app(argc, argv);
    return myApp.exec();
}
MyApplication::MyApplication( int& argc, char** argv ) : 
    QApplication( argc, argv )
{
    m_window= new MyWidget();
    m_worker= new MyWorker();
    m_threadWorker = new QThread;
    m_worker->moveToThread(m_threadWorker);
    connect(this, SIGNAL(aboutToQuit()),m_worker,SLOT(quit()));
    connect(m_worker, SIGNAL(finished()), m_worker, SLOT(deleteLater()));
    connect(m_worker, SIGNAL(finished()), m_threadWorker, SLOT(quit()));
    connect(m_threadWorker, SIGNAL(finished()), m_threadWorker, SLOT(deleteLater()));
    m_threadWorker->start();
    m_window->show();
}
MyApplication::~MyApplication()
{
    m_window->deleteLater();
    qDebug()<<"MyApplication::~MyApplication()";
}
MyWorker::quit()
{
    //longer ending operations freeing resources
    emit finished();
    qDebug() << "MyWorker::quit() emit finished()";
}
MyWorker::~MyWorker()
{
    qDebug() << "MyWorker::~MyWorker()";
}

问题是 Worker 析构函数通常不会运行。我担心没有正确结束工作线程会不时导致应用程序崩溃。我在该线程中使用了相机,因此如果相机循环处于活动状态,则释放需要更多时间,并且通常永远不会发出完成的内容,因此永远不会调用析构函数。

问题是aboutToQuit不会等待工人完成。您必须显式等待它这样做:

connect(this, &MyApplication::aboutToQuit,
        this, &MyApplication::stopWorker);
// also, change up your connects a little to make shure everything gets deleted properly
connect(m_worker, &MyWorker::finished, 
        m_threadWorker, &QThread::quit,
        Qt::DirectConnection); //direct connection is needed, because you are blocking the main thread by waiting
connect(m_threadWorker, &QThread::finished,
        m_worker, &MyWorker::deleteLater);

MyApplication::stopWorker() {
    QMetaObject::invokeMethod(m_worker, "quit");
    m_threadWorker->wait();
    m_threadWorker->deleteLater();
}

但是,这将在等待工作人员完成时"冻结"您的应用程序。如果要在等待时保持响应,请改用 MyApplication::stopWorker 中的本地QEventLoop,并将其用作:

MyApplication::stopWorker() {
    QEventLoop stopLoop;
    connect(m_threadWorker, &QThread::finished,
            &stopLoop, &QEventLoop::quit);
    QMetaObject::invokeMethod(m_worker, "quit");
    stopLoop.exec();
    m_threadWorker->deleteLater();
}

感谢您的评论,此解决方案有效

int main(int argc, char *argv[])
{
    MyApplication app(argc, argv);
    return myApp.exec();
}
MyApplication::MyApplication( int& argc, char** argv ) : 
QApplication( argc, argv )
{
    m_window= new MyWidget();
    m_worker= new MyWorker();
    m_threadWorker = new QThread;
    m_worker->moveToThread(m_threadWorker);
    connect(this, SIGNAL(aboutToQuit()),m_worker,SLOT(quit()),Qt::QueuedConnection);
    connect(m_worker, SIGNAL(finished()), m_threadWorker, SLOT(quit()),Qt::DirectConnection);
    connect(m_threadWorker, SIGNAL(finished()), m_worker, SLOT(deleteLater()));
    m_threadWorker->start();
    m_window->show();
}
MyApplication::~MyApplication()
{
    m_threadWorker->wait();
    m_threadWorker->deleteLater();
    m_window->deleteLater();
    qDebug()<<"MyApplication::~MyApplication()";
}
MyWorker::quit()
{
    //longer ending operations freeing resources
    emit finished();
    qDebug() << "MyWorker::quit() emit finished()";
}
MyWorker::~MyWorker()
{
   qDebug() << "MyWorker::~MyWorker()";
}

最新更新