簡體   English   中英

如何在應用程序退出()期間處理 Qthread 終止?

[英]How to handle Qthread termination during app quit()?

我已經閱讀了許多 stackoverflow 的答案和一些博客文章(也包括 QThread 文檔),但我仍然不確定如何在 QThreads 仍在運行時處理退出的主應用程序(同時不會使應用程序崩潰)。 使這變得困難的是,這些 QThread 實例包含不同類型的阻塞函數,例如 curl 查詢、c++ 文件 io 等。這使得使用 isInterruption 請求的 API 變得困難(我會在理想情況下使用)。 最重要的是,我必須確保它們在 Linux、Windows 和 OSX 上都能正常工作。 我們可以在這里假設任何文件 io 損壞或不完整的網絡查詢都不會讓我們擔心並且會得到處理。 這是壓縮的整個工作示例。 我以兩種不同的方式使用 Qthreads,我將在這里演示,一般的想法是將應用程序的aboutToQuit()與線程的terminate()綁定,假設這是安全的,因為應用程序無論如何都會關閉 -


  1. 工人/控制器

     class Worker : public QObject { Q_OBJECT public slots: void doWork(const QString &msg) { QThread::sleep(10); emit resultReady("Finished"); } // simulates thread doing work signals: void resultReady(const QString &result); }; class Controller : public QObject { Q_OBJECT QThread workerThread; public: Controller() { Worker *worker = new Worker; worker->moveToThread(&workerThread); connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); connect(this, &Controller::operate, worker, &Worker::doWork); connect(worker, &Worker::resultReady, this, &Controller::handleResults); connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(terminateThread())); workerThread.start(); } ~Controller() { workerThread.quit(); workerThread.wait(); } public slots: void handleResults(const QString &msg); void terminateThread() { workerThread.terminate(); workerThread.wait(); } signals: void operate(const QString &msg); }; // can be started like Controller c; emit c.operate("Starting Thread");

  1. 方法 run() 覆蓋

     class WorkerThread : public QThread { Q_OBJECT void run() override { QThread::sleep(10); emit resultReady("Finished");} signals: void resultReady(const QString &s); public slots: void terminateThread() { workerThread.terminate(); workerThread.wait(); } }; class MyObject : public QObject { Q_OBJECT public slots: void handleResults(const QString &msg); public: void startWorkInAThread() { WorkerThread *workerThread = new WorkerThread(); connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults); connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater); connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), workerThread, SLOT(terminateThread())); workerThread->start(); } }; // can be started like MyObject obj; obj.startWorkInAThread();

我使用 main() 測試這兩種方法,看起來像 -

    QCoreApplication a(argc, argv);
    std::puts("Starting app");
    //    Controller c;
    //    emit c.operate("Starting Thread");

    MyObject obj;
    obj.startWorkInAThread();

    QTimer::singleShot(2000, [&]{
        std::puts("Quit pressed");
        a.quit();
    });
    return a.exec();

現在的問題——

  1. 如果我使用 Controller 方法,Linux 會給出一些關於退出時未捕獲異常的錯誤消息。 如果我刪除 .wait() 調用,該消息就會消失,但這些調用是必要的。 Windows 退出正常,但返回代碼是一些負的大數。 OSX 使應用程序崩潰,可能是由於 .wait() 調用。

     Qt has caught an exception thrown from an event handler. Throwing exceptions from an event handler is not supported in Qt. You must not let any exception whatsoever propagate through Qt code. If that is not possible, in Qt 5 you must at least reimplement QCoreApplication::notify() and catch all exceptions there. (process:3416): GLib-CRITICAL **: 22:45:51.656: g_source_unref_internal: assertion 'source != NULL' failed
  2. 如果我使用 run() 覆蓋,Linux 工作得很好,OSX 也是如此。 在 Windows 上,程序永遠不會完成,停留在 .terminate() 調用上,或者如果我刪除它然后在 .wait() 調用上。

  3. 還有一些用法(在實際應用中,不在給定的例子中),其中使用了 run() 覆蓋,但 run 方法的所有者類被初始化為 - WorkerThread *workerThread = new WorkerThread(this); 並且由於this被設置為它的父級,它在退出時以某種方式崩潰了程序。

  4. 我實際上不想等待線程並希望它們在我的程序退出時盡快退出,一些阻塞的網絡操作可能需要幾分鍾才能完成。


我想我已經詳細解釋了所有內容,但總而言之,我希望我的應用程序在運行后台線程時優雅地退出並且根本不會崩潰。 並在所有支持(提及)的 QT 平台上執行此操作。

在您的示例項目中,只需在Controller::terminateThread()方法中將workerThread.quit()替換為workerThread.terminate()

Qt 文檔中將QThread::terminate()的使用描述為危險且不鼓勵使用。 使用QThread::quit()允許工作線程事件循環在長時間工作(睡眠)后輕輕處理這個。

正如您所說,使長時間運行的任務完全可中斷的最佳方法應該是使用QThread::requestInterruption系統並在長時間操作期間檢查是否請求中斷。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM