2

在我的 Qt 应用程序中,我必须执行一些计算量很大的任务,通常是从磁盘(单线程)加载大量数据集。任务中的代码严重依赖于适当的异常处理,并且严格来说是非 Qt。我使用 将这些任务从 GUI 线程中卸载QtConcurrent::run(),以便显示进度条。但是,正如我从 Qt 文档中了解到的那样,我无法在 GUI 线程中捕获异常。我知道理论上这没有意义。但是,在实践中,由于进度条,我只使用线程。处理这种情况的最佳方法是什么?

编辑:我想强调的是,我不需要对卸载的工作进行细粒度控制。我真的只是卸载它以显示进度条。这可能是其他人也遇到过的情况。

4

3 回答 3

1

您可以将整个函数包装到一个 try/catch 中。当捕获到异常时,您可以使用自定义信号通知 GUI 线程。

您还可以在 GUI 线程中运行您的函数并QApplication::processEvents()定期调用以更新 UI(进度条等)。

于 2013-06-26T21:42:10.893 回答
1

我现在让它工作了。我没有直接调用QtConcurrent::run,而是使用能够捕获非 Qt 异常的 Qt 包装器。当捕获到异常时,将其推送到主线程到排队连接并重新抛出。

    namespace MyConcurrent {

    template <class U, class V>
    QFuture<U> offload(V func)
    {       
        U (*caller)(V) = offloaded_placeholder<U>;
        return QtConcurrent::run(caller, func);
    }

    template <class U, class V>
    U offloaded_placeholder(V func)
    {
        try
        {       
            return func();
        }
        catch(Utilities::ExceptionBase& e)
        {
            qRegisterMetaType<Utilities::ExceptionBase>("Utilities::ExceptionBase");
            QMetaObject::invokeMethod(ConcurrencyCommunicator::getInstance(), "onRequestPushExceptionToMainThread", Qt::QueuedConnection, Q_ARG(const Utilities::ExceptionBase&, e));           
        }
    }

    }

用法:

    QFuture<ret_type> = MyConcurrent::offload<ret_type>(std::bind(&some_func, params));

请注意,这Utilities::ExceptionBase是一个源自标准异常的类。ConcurrencyCommunicator是一个简单的类,GUI 有一个指向它的指针。推送的异常在内部重新抛出ConcurrencyCommunicator,然后被主线程的事件循环捕获。

于 2014-12-08T12:53:18.943 回答
-1

我要提前说我没有使用过Qt。话虽如此,如果可以的话,您应该尝试在线程之间共享变量。使用一些全局变量或指针将一个线程的状态传达给另一个线程(不要忘记并发是一个潜在问题)。

您还应该考虑哪个线程领先,哪个线程跟随。您确定要让 gui 线程控制正在读取数据的线程吗?您是否可以让正在加载数据的线程只处理自己的异常并将其进度传达给 gui 线程?为什么gui线程是中央/控制/主线程?

抱歉,我不能提供更多建议,但祝你的程序好运:)

于 2013-06-26T23:02:06.353 回答