什么';捕捉在不同线程中运行的方法的异常的正确方法是什么? 我用C++插件运行QML应用程序。应用程序非常简单: QApplication app(argc, argv); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:///ui/views/mainwindow.qml"))); return app.exec();
但是qml插件有很多代码。为了避免在qml中冻结,我通过什么';捕捉在不同线程中运行的方法的异常的正确方法是什么? 我用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 (
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());
}
});
}