Use SemaphoreSlim to ensure cache only remove once

This commit is contained in:
Kevin Zhang 2021-07-31 16:23:58 +08:00
parent 710d2a89a2
commit a0835288e2

View file

@ -2,6 +2,7 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Media;
@ -26,6 +27,7 @@ namespace Flow.Launcher.Infrastructure.Image
private const int MaxCached = 50;
public ConcurrentDictionary<string, ImageUsage> Data { get; private set; } = new ConcurrentDictionary<string, ImageUsage>();
private const int permissibleFactor = 2;
private SemaphoreSlim semaphore = new(1, 1);
public void Initialization(Dictionary<string, int> usage)
{
@ -35,8 +37,6 @@ namespace Flow.Launcher.Infrastructure.Image
}
}
private volatile bool removing;
public ImageSource this[string path]
{
get
@ -62,15 +62,22 @@ namespace Flow.Launcher.Infrastructure.Image
}
);
// To prevent the dictionary from drastically increasing in size by caching images, the dictionary size is not allowed to grow more than the permissibleFactor * maxCached size
// This is done so that we don't constantly perform this resizing operation and also maintain the image cache size at the same time
if (Data.Count > permissibleFactor * MaxCached && !removing)
SliceExtra();
async void SliceExtra()
{
removing = true;
// To delete the images from the data dictionary based on the resizing of the Usage Dictionary.
foreach (var key in Data.OrderBy(x => x.Value.usage).Take(Data.Count - MaxCached).Select(x => x.Key))
Data.TryRemove(key, out _);
removing = false;
// To prevent the dictionary from drastically increasing in size by caching images, the dictionary size is not allowed to grow more than the permissibleFactor * maxCached size
// This is done so that we don't constantly perform this resizing operation and also maintain the image cache size at the same time
if (Data.Count > permissibleFactor * MaxCached)
{
await semaphore.WaitAsync();
// To delete the images from the data dictionary based on the resizing of the Usage Dictionary
// Double Check to avoid concurrent remove
if (Data.Count > permissibleFactor * MaxCached)
foreach (var key in Data.OrderBy(x => x.Value.usage).Take(Data.Count - MaxCached).Select(x => x.Key).ToArray())
Data.TryRemove(key, out _);
semaphore.Release();
}
}
}
}