gpt4 book ai didi

c++ - 如何在应用程序退出()期间处理 Qthread 终止?

转载 作者:行者123 更新时间:2023-12-02 09:37:46 24 4
gpt4 key购买 nike

我已经阅读了许多 stackoverflow 答案和一些博客文章(也包括 QThread 文档),但我仍然不确定如何在 QThreads 仍在运行时处理退出的主应用程序(而不是同时崩溃应用程序)。使这变得困难的事实是,这些 QThread 实例包含不同类型的阻塞函数,例如 curl 查询、c++ 文件 io 等。这使得使用 isInterruption 请求的 API 变得很困难(我会在理想情况下使用它)。最重要的是,我必须确保这些在 Linux、Windows 和 OSX 上都能正常工作。我们可以在这里假设任何文件 io 损坏或不完整的网络查询都不会让我们担心并得到照顾。这是整个工作示例zipped .我以两种不同的方式使用Qthreads,我将在这里演示,总体思路是绑定(bind)应用程序的aboutToQuit()带线程的terminate()假设这是安全的,因为无论如何应用程序都会关闭 -

  • worker / Controller
     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");
  • 方法 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();

    现在的问题 -
  • 如果我使用 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
  • 如果我使用 run() 覆盖,Linux 工作得非常好,OSX 也是如此。在 Windows 上,程序永远不会完成,卡在 .terminate() 调用上,或者如果我删除它,然后在 .wait() 调用上。
  • 还有一些用法(在实际应用中,不在给定示例中)使用 run() 覆盖但 run 方法的所有者类被初始化为 - WorkerThread *workerThread = new WorkerThread(this);由于this被设置为它的父级,它以某种方式在退出时使程序崩溃。
  • 我实际上不想等待线程并希望它们在我的程序退出时尽快退出,一些阻塞的网络操作可能需要几分钟才能完成。

  • 我想我已经详细解释了所有内容,但总而言之,我希望我的应用程序在运行后台线程的情况下优雅地退出,并且根本不会崩溃。并在所有受支持(提及)的 QT 平台上执行此操作。

    最佳答案

    在您的示例项目中,只需替换 workerThread.terminate()通过 workerThread.quit()Controller::terminateThread()方法。QThread::terminate()的用法被描述为 dangerous and discouraged在 Qt 文档中。使用 QThread::quit()允许工作线程事件循环在他长时间工作( sleep )后轻轻地处理这个问题。
    正如您所说,使长时间运行的任务完全可中断的最佳方法应该是使用 QThread::requestInterruption系统并在长时间运行期间检查是否请求中断。

    关于c++ - 如何在应用程序退出()期间处理 Qthread 终止?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64124784/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com