I'm experimenting with the concurrent run with promise functionality from Qt6. How can I catch, from the GUI thread, any exception thrown in the worker thread?
void MainWindow::on_pushButton_startTask_clicked()
{
auto lambda = [](QPromise<void>& promise)
{
// Cancel the task if requested
while (!promise.isCanceled())
{
// Do some long computation...
if (<something-has-failed>)
throw std::runtime_error("The task has failed");
}
};
this->future = QtConcurrent::run(lambda);
// Connect the watcher to the finished signal
connect(&this->watcher, &QFutureWatcher<void>::finished, this, &MainWindow::on_taskFinished);
this->watcher.setFuture(this->future);
}
void MainWindow::on_taskFinished()
{
// How to catch the exception here?
}
I've tried by doing the following two things:
- Adding
onFailedin theon_taskFinished:
void MainWindow::on_taskFinished()
{
this->future.onFailed([](const std::exception& ex)
{
std::cout << ex.what();
});
}
- Adding
onFailedafter callingQtConcurrent::run:
void MainWindow::on_pushButton_startTask_clicked()
{
...
this->future = QtConcurrent::run(lambda)
.onFailed([](const std::exception& ex)
{
std::cout << ex.what();
});
...
}
In both cases the code passes from the onFailed block, but the exception is not the one thrown from the lambda, it looks like an empty default excetion (maybe something from Qt?), whose what content is Unknown exception.
You may use
onFailedwith app context e.g.qAppis just macro for: QCoreApplication::instance()It is little bit tricky to use
QtConcurrent::runprefer to use explicit context. Otherwise you may end up with issues like me when lambda executes so quick that you will "inherit wrong context". E.g.so prefer using: (or with QObject* context)
Watchout for:
QUnhandledExceptionExample how to handle it (to unwrap your exception):