如何正确处置 MemoryCache 中过期的对象(它可能仍在使用中)?

问题描述 投票:0回答:1

我了解

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();
                        }
                    }
                }
            });

            // ...
        }
c# .net caching dispose memorycache
1个回答
0
投票

我实现了一个像这样的简单跟踪器:

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
© www.soinside.com 2019 - 2024. All rights reserved.