Reputation: 1766
In my Qt application I have to perform some computationally heavy tasks, typically loading huge datasets from disk (single-threaded). The code in the task heavily relies on proper exception handling and is strictly non-Qt.
I offload these tasks from the GUI thread using QtConcurrent::run()
, so that I can show a progress bar. However as I understand from the Qt docs, I can't catch exceptions in the GUI thread. I understand that theoretically this would not make sense. However, in practice I only use threading because of the progress bar. What is the best way to deal with this situation?
Edit: I'd like to emphasize that I do not need fine grained control over the offloaded work. I really only offload it to show a progress bar. This is probably a situation others have encountered as well.
Upvotes: 2
Views: 358
Reputation: 1766
I made it work now. Instead of calling QtConcurrent::run
directly, I use a Qt wrapper which is able to catch non-Qt exceptions. When an exception is caught, it is pushed to the main thread to a queued connection and rethrown.
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));
}
}
}
Usage:
QFuture<ret_type> = MyConcurrent::offload<ret_type>(std::bind(&some_func, params));
Please note that Utilities::ExceptionBase
is a class deriving from standard exceptions. ConcurrencyCommunicator
is a simple class, to which the GUI has a pointer. The pushed exception is rethrown inside ConcurrencyCommunicator
and then caught by the main thread's event loop.
Upvotes: 1
Reputation: 23
I am going to say upfront that I have not used Qt. That being said, if you can, you should try and share variables between the threads. Use a few global variables or pointers to communicate the state of one thread to the other (don't forget that concurrency is a potential issue).
You should also consider which thread is leading and which is following. Are you sure that you want the gui thread controlling the thread that is reading data? Could you possibly have the thread that is loading data just handle its own exceptions and communicate its progress to the gui thread? Why is the gui thread the central/controlling/main thread?
Sorry I cant offer more advice, but good luck with your program :)
Upvotes: -1
Reputation: 40512
You can wrap your entire function into one try/catch. When an exception is caught, you can notify GUI thread using a custom signal.
Also you can run your function in GUI thread and call QApplication::processEvents()
periodically to update the UI (progress bars, etc).
Upvotes: 1