1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-09 23:34:20 +00:00

LruCache: Make the LRU cache implementation thread safe

This commit is contained in:
Anthony Nicholls 2025-07-30 13:35:11 +01:00 committed by Anthony Nicholls
parent c1affc0a0e
commit 667b3fae86
3 changed files with 35 additions and 6 deletions

View file

@ -43,6 +43,8 @@ public:
template <typename Fn>
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<std::mutex> mutex = std::make_unique<std::mutex>();
};
} // namespace juce

View file

@ -479,7 +479,7 @@ RectangleListSpriteBatch::~RectangleListSpriteBatch()
void RectangleListSpriteBatch::release()
{
whiteRectangle = nullptr;
spriteBatches = {};
spriteBatches.clear();
destinations.free();
destinationsCapacity = 0;
}

View file

@ -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<Key, std::vector<GlyphLayer>> cache;
CriticalSection lock;
static GlyphCache*& getSingletonPointer() noexcept
{