MemoryCache
中的物品过期后不会被丢弃。我正在缓存一些 X509Certificate2
根据文档,应该在完成后进行处理。
但是,当对象可能仍被某些线程使用时,我的天真的方法会处置该对象(请参见下面的代码)。
我该如何正确处理这种情况?我想我可能需要引用计数或类似的东西?
await cache.GetOrCreateAsync("IdTokenCerts", async entry =>
{
entry.AbsoluteExpirationRelativeToNow = JwtCertsCacheLifetime;
entry.RegisterPostEvictionCallback((_, value, _, _) =>
{
if (value is IEnumerable<SecurityKey> keys)
{
foreach (var key in keys)
{
if (key is X509SecurityKey x509Key)
{
x509Key.Certificate.Dispose();
}
}
}
});
// ...
}
我实现了一个像这样的简单跟踪器:
public class UsageTracker<TData>(TData data)
{
public event EventHandler OnDisposed = delegate { };
public bool DisposeRequested { get; private set; }
public TData Data => data;
public int UsageCount { get; private set; }
public void RequestDispose()
{
if (DisposeRequested) { return; }
DisposeRequested = true;
CheckForDispose();
}
public UsageTrackerItem<TData> RequestUsage()
{
if (DisposeRequested)
{
throw new ObjectDisposedException(nameof(UsageTracker<TData>));
}
UsageCount++;
return new UsageTrackerItem<TData>(this, data);
}
internal void OnItemDisposed()
{
UsageCount--;
CheckForDispose();
}
void CheckForDispose()
{
if (UsageCount == 0 && DisposeRequested)
{
OnDisposed(this, EventArgs.Empty);
}
}
}
public class UsageTrackerItem<TData> : IDisposable
{
readonly UsageTracker<TData> tracker;
public TData Data { get; private set; }
internal UsageTrackerItem(UsageTracker<TData> tracker, TData data)
{
this.tracker = tracker;
Data = data;
}
public void Dispose()
{
tracker.OnItemDisposed();
}
}
用途:
var data = 5;
var tracker = new UsageTracker<int>(data);
// Test tracker
tracker.OnDisposed += (sender, e) => Console.WriteLine("Data actually disposed");
var task = Task.WhenAll(Enumerable.Range(0, 10).Select(async i =>
{
using var data = tracker.RequestUsage();
await Task.Delay(Random.Shared.Next(1000, 5000));
Console.WriteLine($"Task {i} completed.");
}));
tracker.RequestDispose();
Console.WriteLine("Tracker disposal requested");
await task;
输出:
Tracker disposal requested
Task 3 completed.
Task 0 completed.
Task 8 completed.
Task 9 completed.
Task 4 completed.
Task 7 completed.
Task 5 completed.
Task 1 completed.
Task 6 completed.
Task 2 completed.
Data actually disposed