在不同线程中捕获方法 运行 异常的正确方法是什么?
What's the proper way of catching an exception of method running in a different thread?
我是 运行 带有 C++ 插件的 qml 应用程序。申请非常简单:
QApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:///ui/views/mainwindow.qml")));
return app.exec();
但是qml插件代码比较多。为了避免在 qml 中冻结,我通过 moveToThread()
将对象放入线程中,并通过使用 Qt::QueuedConnection
参数异步调用 QMetaObject::invokeMethod()
的方法。问题是我通过 invokeMethod
调用的方法会抛出异常,然后程序会崩溃,因为我无法捕获它们:
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_INVOKABLE
并且 ThisClass
实例被移动到另一个线程。
使用 lambda 的可能解决方案
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);
将 lambda 与 QtConcurrent (Victor Polevoy) 结合使用的解决方案
void ThisClass::performDisconnect() {
QtConcurrent::run([this]() {
try {
this->qlNetwork.disconnect();
} catch (const std::runtime_error& e) {
emit error(e.what());
}
});
}
我是 运行 带有 C++ 插件的 qml 应用程序。申请非常简单:
QApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:///ui/views/mainwindow.qml")));
return app.exec();
但是qml插件代码比较多。为了避免在 qml 中冻结,我通过 moveToThread()
将对象放入线程中,并通过使用 Qt::QueuedConnection
参数异步调用 QMetaObject::invokeMethod()
的方法。问题是我通过 invokeMethod
调用的方法会抛出异常,然后程序会崩溃,因为我无法捕获它们:
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_INVOKABLE
并且 ThisClass
实例被移动到另一个线程。
使用 lambda 的可能解决方案
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);
将 lambda 与 QtConcurrent (Victor Polevoy) 结合使用的解决方案
void ThisClass::performDisconnect() {
QtConcurrent::run([this]() {
try {
this->qlNetwork.disconnect();
} catch (const std::runtime_error& e) {
emit error(e.what());
}
});
}