防止两个线程进入具有相同值的代码块

pow*_*tte 11 c# multithreading locking

假设我有这个功能(假设我以线程安全的方式访问Cache):

object GetCachedValue(string id)
{
    if (!Cache.ContainsKey(id))
    {
         //long running operation to fetch the value for id
         object value = GetTheValueForId(id);
         Cache.Add(id, value);
    }     
    return Cache[id];
}
Run Code Online (Sandbox Code Playgroud)

我想阻止两个线程同时运行" 长时间运行"操作一个值.显然我可以将整个东西包装在一个lock()中,但是整个函数会阻塞而不管值是什么,我希望两个线程能够执行长时间运行操作,只要它们正在寻找不同的id.

是否存在基于值锁定的内置锁定机制,因此一个线程可以在另一个线程完成长时间运行操作时阻塞,因此我不需要执行两次(或N次)?理想情况下,只要在一个线程中执行长时间运行操作,其他线程就不应该为相同的id值执行此操作.

我可以通过将id放在HashSet中然后在操作完成后删除它们来自己滚动,但这看起来像是一个黑客.

L.B*_*L.B 7

我会Lazy<T>在这里使用.下面的代码将锁定缓存,将其Lazy放入缓存并立即返回.长时间运行操作将以线程安全方式执行一次.

new Thread(() => Console.WriteLine("1-" + GetCachedValue("1").Value)).Start();
new Thread(() => Console.WriteLine("2-" + GetCachedValue("1").Value)).Start();
Run Code Online (Sandbox Code Playgroud)
Lazy<object> GetCachedValue(string id)
{
    lock (Cache)
    {
        if (!Cache.ContainsKey(id))
        {
            Lazy<object> lazy = new Lazy<object>(() =>
                {
                    Console.WriteLine("**Long Running Job**");
                    Thread.Sleep(3000);
                    return int.Parse(id);
                }, 
                true);

            Cache.Add(id, lazy);
            Console.WriteLine("added to cache");
        }
        return Cache[id];
    }
}
Run Code Online (Sandbox Code Playgroud)