From 65a229211d8fcea5ead6f6907b15b356163c4da5 Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Tue, 24 Oct 2023 15:06:01 -0600 Subject: [PATCH] Use std::shared_mutex in get_fe_by_name(). --- include/deal.II/fe/fe_tools.templates.h | 58 ++++++++++++++----------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/include/deal.II/fe/fe_tools.templates.h b/include/deal.II/fe/fe_tools.templates.h index f093b1bb6d..82469926cd 100644 --- a/include/deal.II/fe/fe_tools.templates.h +++ b/include/deal.II/fe/fe_tools.templates.h @@ -69,6 +69,7 @@ #include #include #include +#include DEAL_II_NAMESPACE_OPEN @@ -1227,7 +1228,7 @@ namespace FETools // it belongs to an internal namespace) in order to make icc happy // (which otherwise reports a multiply defined symbol when linking // libraries for more than one space dimension together) - static std::mutex fe_name_map_lock; + static std::shared_mutex fe_name_map_lock; // This is the map used by FETools::get_fe_by_name and // FETools::add_fe_name. It is only accessed by functions in this @@ -2294,25 +2295,32 @@ namespace FETools "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_")); if (name_end < name.size()) name.erase(name_end); - // first make sure that no other - // thread intercepts the - // operation of this function; - // for this, acquire the lock - // until we quit this function - std::lock_guard lock( - internal::FEToolsAddFENameHelper::fe_name_map_lock); - Assert( - internal::FEToolsAddFENameHelper::get_fe_name_map()[dim][spacedim].find( - name) == - internal::FEToolsAddFENameHelper::get_fe_name_map()[dim][spacedim] - .end(), - ExcMessage("Cannot change existing element in finite element name list")); - - // Insert the normalized name into - // the map - internal::FEToolsAddFENameHelper::get_fe_name_map()[dim][spacedim][name] = - std::unique_ptr(factory); + // Ensure that the element we are looking for isn't in the map + // yet. This only requires us to read the map, so it can happen + // in a shared locked state +#if DEBUG + { + std::shared_lock lock( + internal::FEToolsAddFENameHelper::fe_name_map_lock); + + Assert( + internal::FEToolsAddFENameHelper::get_fe_name_map()[dim][spacedim].find( + name) == + internal::FEToolsAddFENameHelper::get_fe_name_map()[dim][spacedim] + .end(), + ExcMessage( + "Cannot change existing element in finite element name list")); + } +#endif + + + // Insert the normalized name into the map. This changes the map, so it + // has to happen under a non-shared (writer) lock: + std::unique_lock lock( + internal::FEToolsAddFENameHelper::fe_name_map_lock); + internal::FEToolsAddFENameHelper::get_fe_name_map()[dim][spacedim].emplace( + name, std::unique_ptr(factory)); } @@ -2456,16 +2464,16 @@ namespace FETools } else { - // Make sure no other thread - // is just adding an element - std::lock_guard lock( + // Lock access to the name map, but do so in a way that allows other + // readers to access it concurrently: + std::shared_lock lock( internal::FEToolsAddFENameHelper::fe_name_map_lock); + AssertThrow(fe_name_map.find(name_part) != fe_name_map.end(), FETools::ExcInvalidFEName(name)); - // Now, just the (degree) - // or (Quadrature<1>(degree+1)) - // part should be left. + // Now, just the (degree) or (Quadrature<1>(degree+1)) part should + // be left. if (name.empty() || name[0] != '(') throw std::string("Invalid first character in ") + name; name.erase(0, 1); -- 2.39.5