From: Wolfgang Bangerth Date: Mon, 26 Jun 2023 19:03:10 +0000 (-0600) Subject: Ensure we set a flag correctly even if a task ends in an exception. X-Git-Tag: v9.5.0-rc1~12^2~1 X-Git-Url: https://gitweb.dealii.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fc5599973e335e3f9b5a6127a210f40b1084b852;p=dealii.git Ensure we set a flag correctly even if a task ends in an exception. --- diff --git a/include/deal.II/base/thread_management.h b/include/deal.II/base/thread_management.h index 6a6fa12a2f..b41dc02096 100644 --- a/include/deal.II/base/thread_management.h +++ b/include/deal.II/base/thread_management.h @@ -239,6 +239,11 @@ namespace Threads value = std::move(v); } + /** + * Set the value from the given `std::future` object. If the future + * object holds an exception, the set will not happen and this function + * instead throws the exception stored in the future object. + */ inline void set_from(std::future &v) { @@ -291,6 +296,11 @@ namespace Threads value = &v; } + /** + * Set the value from the given `std::future` object. If the future + * object holds an exception, the set will not happen and this function + * instead throws the exception stored in the future object. + */ inline void set_from(std::future &v) { @@ -327,6 +337,12 @@ namespace Threads {} + /** + * This function does nothing, because the `std::future` object + * does not actually hold a return value. However, if the future + * object holds an exception, the set will not happen and this function + * instead throws the exception stored in the future object. + */ inline void set_from(std::future &) {} @@ -1397,9 +1413,26 @@ namespace Threads // to future.wait() in the set_from() function. Avoid the // issue by just explicitly calling future.wait() here.) future.wait(); - returned_object.set_from(future); - // Now we can safely set the flag and return. + // Acquire the returned object. If the task ended in an + // exception, `set_from` will call `std::future::get`, which + // will throw an exception. This leaves `returned_object` in + // an undefined state, but moreover we would bypass setting + // `task_has_finished=true` below. So catch the exception + // for just long enough that we can set that flag, and then + // re-throw it: + try + { + returned_object.set_from(future); + } + catch (...) + { + task_has_finished = true; + throw; + } + + // If we got here, the task has ended without an exception and + // we can safely set the flag and return. task_has_finished = true; } }