是我的c#实现的字典与项目过期安全吗?



我在c#和线程的早期工作,我需要一个数据结构,可以像字典一样存储键值对,但在添加一定时间后,我希望值"过期",或者从字典中删除。

我已经提出了一个实现,似乎工作,但我想知道是否有可能有任何问题,当它在多线程环境中使用。

  1. 我目前的执行有任何直接问题吗?
  2. 由于字典的所有使用都受到信号量的保护,这个实现是否被认为是线程安全的?
public class TokenCache<TKey, TValue>
where TKey : IEquatable<TKey>
where TValue : class
{
private readonly TimeSpan expirationTime;
private readonly SemaphoreSlim semaphore;
private readonly Dictionary<TKey, TValue> cache;
public TokenCache(TimeSpan expirationTime)
{
this.expirationTime = expirationTime;
this.semaphore = new SemaphoreSlim(1, 1);
this.cache = new Dictionary<TKey, TValue>();
}
public void Add(TKey key, TValue value)
{
this.semaphore.Wait();
try
{
this.cache[key] = value;
Task
.Run(() => Thread.Sleep(this.expirationTime))
.ContinueWith(t =>
{
this.Remove(key);
});
}
finally
{
this.semaphore.Release();
}
}
public void Remove(TKey key)
{
this.semaphore.Wait();
try
{
this.cache.Remove(key);
}
finally
{
this.semaphore.Release();
}
}
public TValue GetValueOrDefault(TKey key)
{
this.semaphore.Wait();
try
{
if (this.cache.TryGetValue(key, out var value))
{
return value;
}
return null;
}
finally
{
this.semaphore.Release();
}
}
}

我看到的问题没有特别的顺序(可能有更多):

任务。运行

Task.Run(() => Thread.Sleep(...))是一个非常糟糕的主意。ThreadPool包含运行Tasks的线程,其线程数量有限(它可以增长,但增长非常缓慢!!),并且通过调用Task.Run(() => Thread.Sleep(...))而不是Task.Delay(...),您在等待期间浪费了一个ThreadPool线程。Task.Delay(...)不占用线程

项目过期错误

另一个问题是你的Add方法。考虑以下内容:

  • 创建TokenCache的实例,例如通过new TokenCache<int, string>(TimeSpan.FromMinutes(1))
  • 呼叫Add(10, "ten")
  • 50秒后,呼叫Remove(10)
  • 5秒后,呼叫Add(10, "The Number 10");
  • 因为你已经写了你的Add方法,你现在要删除值"The Number 10"后,只有5秒

毫无意义的信号而且,我真的不明白使用SemaphoreSlim的意义。在这种情况下,您可以在private readonly object locker = new();

上使用lock关键字

最新更新