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

Posted

技术标签:

【中文标题】捕获在不同线程中运行的方法异常的正确方法是啥?【英文标题】:What's the proper way of catching an exception of method running in a different thread?捕获在不同线程中运行的方法异常的正确方法是什么? 【发布时间】:2015-01-21 07:50:48 【问题描述】:

我正在运行一个带有 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)中的对象捕获异常?

【问题讨论】:

【参考方案1】:

您将创建一个从另一个线程调用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);

在 QtConcurrent (Victor Polevoy) 中使用 lambda 的解决方案

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

【讨论】:

是的,我已经考虑过了,但是对于这种常见情况,这里没有通用的解决方案吗? 通用解决方案是什么意思?异常必须在执行方法调用的同一线程中同步处理。 我的意思是一个解决方案,它可以在没有任何包装器的情况下做到这一点。例如,QThread::run 的一些内部 qt 包装器会捕获 (...) 并发出一些信号或类似的东西。 好的,我至少可以用 lambdas 做到这一点吗?我的尝试没有成功。 我添加了 QtConcurrent 的解决方案,由我亲自测试。

以上是关于捕获在不同线程中运行的方法异常的正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

java语言中application异常退出和线程异常崩溃的捕获方法,并且在捕获的钩子方法中进行异常处理

从另一个线程捕获异常

在 C++ 中的两个线程之间同步变量的正确方法是啥?

java中error与exception的区别是啥?

捕获不同线程中引起的异常[重复]

在任务中捕获异常的最佳方法是啥?