捕获在不同线程中运行的方法的异常的正确方法是什么?

时间:2015-01-21 07:50:48

标签: c++ multithreading qt exception qthread

我正在使用C ++插件运行qml应用程序。应用程序非常简单:

QApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:///ui/views/mainwindow.qml")));

return app.exec();

但是qml插件有很多代码。为避免在qml中出现冻结,我将对象放入moveToThread()的线程中,并使用QMetaObject::invokeMethod()参数异步调用Qt::QueuedConnection方法。问题是我invokeMethod调用的方法可以抛出异常然后程序会崩溃,因为我无法捕获它们:

try {
    QMetaObject::invokeMethod(&qlNetwork, "disconnect", Qt::QueuedConnection);
} catch (const std::runtime_error& e) {
    emit error(e.what());
}

当然这段代码不起作用,因为调用是非阻塞的。问题是:如何从不同线程(QThread)中的对象中捕获异常?

1 个答案:

答案 0 :(得分:2)

您创建一个从另一个线程调用disconnect的包装器槽并处理该异常。

void ThisClass::wrapperMethod() {
    try {
        qlNetwork->disconnect();
    } catch (const std::runtime_error& e) {
        emit error(e.what());
    }
}

然后以异步方式调用包装器方法:

    QMetaObject::invokeMethod(this, "wrapperMethod", Qt::QueuedConnection);

确保wrapperMethodSLOT,或将其定义为Q_INVOKABLE,并将ThisClass实例移至其他主题。


使用lambdas的可能解决方案

QTimer *t = new QTimer();
connect(t, &QTimer::timeout, this, [=]() {
    t->deleteLater();
    try {
        qlNetwork->disconnect();
    } catch (const std::runtime_error& e) {
        emit this->error(e.what());
    }
}, Qt::QueuedConnection);
/* don't forget to move the timer to the thread where
   you want the lambda to be executed*/
t->moveToThread(targetThread);
t->setSingleShot(true);
t->start(0);

使用lambdas和QtConcurrent解决方案(Victor Polevoy)

void ThisClass::performDisconnect() {
    QtConcurrent::run([this]() {
        try {
            this->qlNetwork.disconnect();
        } catch (const std::runtime_error& e) {
            emit error(e.what());
        }
    });
}