什么';捕捉在不同线程中运行的方法的异常的正确方法是什么? 我用C++插件运行QML应用程序。应用程序非常简单: QApplication app(argc, argv); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:///ui/views/mainwindow.qml"))); return app.exec();

什么';捕捉在不同线程中运行的方法的异常的正确方法是什么? 我用C++插件运行QML应用程序。应用程序非常简单: QApplication app(argc, argv); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:///ui/views/mainwindow.qml"))); return app.exec();,c++,multithreading,qt,exception,qthread,C++,Multithreading,Qt,Exception,Qthread,但是qml插件有很多代码。为了避免在qml中冻结,我通过moveToThread()将对象放入线程,并通过QMetaObject::invokeMethod()使用Qt::QueuedConnection参数异步调用方法。问题是,我通过调用方法调用的方法会引发异常,然后程序会崩溃,因为我无法捕获它们: try { QMetaObject::invokeMethod(&qlNetwork, "disconnect", Qt::QueuedConnection); } catch (

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

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

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

您需要创建一个包装槽,从另一个线程调用
disconnect
,并处理异常

void ThisClass::wrapperMethod() {
    try {
        qlNetwork->disconnect();
    } catch (const std::runtime_error& e) {
        emit error(e.what());
    }
}
然后异步调用包装器方法:

    QMetaObject::invokeMethod(this, "wrapperMethod", Qt::QueuedConnection);
确保
wrapperMethod
是一个
SLOT
或者它被定义为
Q\u INVOKABLE
,并且
这个类
实例被移动到另一个线程


使用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)


是的,我已经考虑过了,但对于这种常见的情况,这里没有任何普适解吗?你们所说的普适解是什么意思?异常必须在执行方法调用的同一线程中同步处理。我指的是一种不需要任何包装就可以做到这一点的解决方案。例如,一些
QThread::run
的内部
qt
包装器捕获
(…)
,并发出一些信号或类似的东西。好的,我至少可以用lambdas这样做吗?我的尝试没有成功。我添加了
QtConcurrent
的解决方案,这是我亲自测试的。
void ThisClass::performDisconnect() {
    QtConcurrent::run([this]() {
        try {
            this->qlNetwork.disconnect();
        } catch (const std::runtime_error& e) {
            emit error(e.what());
        }
    });
}