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:
parent
c1affc0a0e
commit
667b3fae86
3 changed files with 35 additions and 6 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -479,7 +479,7 @@ RectangleListSpriteBatch::~RectangleListSpriteBatch()
|
|||
void RectangleListSpriteBatch::release()
|
||||
{
|
||||
whiteRectangle = nullptr;
|
||||
spriteBatches = {};
|
||||
spriteBatches.clear();
|
||||
destinations.free();
|
||||
destinationsCapacity = 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue