diff --git a/modules/juce_core/detail/juce_LruCache.h b/modules/juce_core/detail/juce_LruCache.h index 7154c5606d..901a9bfcf3 100644 --- a/modules/juce_core/detail/juce_LruCache.h +++ b/modules/juce_core/detail/juce_LruCache.h @@ -43,6 +43,8 @@ public: template const Value& get (Key key, Fn&& fn) { + std::unique_lock lock { *mutex }; + if (const auto iter = map.find (key); iter != map.end()) { list.erase (iter->second.listIterator); @@ -50,6 +52,28 @@ public: return iter->second.value; } + const auto localInsertionCounter = insertionCounter; + + // There are two reasons we don't want to have the mutex locked while + // getting the value + // 1. If the operation itself results in a call to the same cache it + // would cause a deadlock. + // 2. The generation of the value is likely to be slow therefore we + // don't want to force other threads to wait on this operation + lock.unlock(); + auto value = fn (key); + lock.lock(); + + // While the mutex was unlocked the value may have already been added to + // the cache. In this case we can skip placing the value at the front as + // it should've already recently been placed at the front. However, we + // still need to skip adding the value to the cache for a second time. + if (localInsertionCounter != insertionCounter) + if (const auto iter = map.find (key); iter != map.end()) + return iter->second.value; + + ++insertionCounter; + while (list.size() >= maxEntries) { const auto toRemove = list.begin(); @@ -57,7 +81,6 @@ public: list.erase (toRemove); } - auto value = fn (key); const auto mapIteratorPair = map.emplace (std::move (key), Pair { std::move (value), {} }); jassert (mapIteratorPair.second); @@ -66,6 +89,13 @@ public: return mapIteratorPair.first->second.value; } + void clear() + { + const std::scoped_lock lock { *mutex }; + list.clear(); + map.clear(); + } + private: struct Pair { @@ -80,6 +110,8 @@ private: typename Pair::Map map; typename Pair::List list; + uint32_t insertionCounter{}; + std::unique_ptr mutex = std::make_unique(); }; } // namespace juce diff --git a/modules/juce_graphics/native/juce_DirectX_windows.cpp b/modules/juce_graphics/native/juce_DirectX_windows.cpp index 09f02ed4e4..1aa24923c0 100644 --- a/modules/juce_graphics/native/juce_DirectX_windows.cpp +++ b/modules/juce_graphics/native/juce_DirectX_windows.cpp @@ -479,7 +479,7 @@ RectangleListSpriteBatch::~RectangleListSpriteBatch() void RectangleListSpriteBatch::release() { whiteRectangle = nullptr; - spriteBatches = {}; + spriteBatches.clear(); destinations.free(); destinationsCapacity = 0; } diff --git a/modules/juce_graphics/native/juce_RenderingHelpers.h b/modules/juce_graphics/native/juce_RenderingHelpers.h index b35401a6e2..8fd08de53a 100644 --- a/modules/juce_graphics/native/juce_RenderingHelpers.h +++ b/modules/juce_graphics/native/juce_RenderingHelpers.h @@ -196,13 +196,11 @@ public: //============================================================================== void reset() { - const ScopedLock sl { lock }; - cache = {}; + cache.clear(); } const auto& get (const Font& font, const int glyphNumber) { - const ScopedLock sl { lock }; return cache.get (Key { font, glyphNumber }, [] (const auto& key) { auto fontHeight = key.font.getHeight(); @@ -233,7 +231,6 @@ private: }; LruCache> cache; - CriticalSection lock; static GlyphCache*& getSingletonPointer() noexcept {