多线程 - 用于初始化共享数据的竞争条件

时间:2016-03-09 11:04:34

标签: c# multithreading wcf caching race-condition

我正在尝试实施以下方案,无法提出解决方案。

在我的Web服务中,我根据会话ID缓存对象(包含静态数据)。收到请求后,它会检查缓存是否包含会话ID的任何密钥。

  1. 如果不可用,它将从DB加载它并将其存储在缓存中。
  2. 如果可用,它会使用该缓存并继续进行进一步处理。
  3. 现在,在此服务中启用了多线程,并且当多个请求(具有相同的会话ID)被发送到服务时,所有这些请求都试图将数据加载到缓存中,因为它们最初都没有找到该密钥。

    问题是:我想停止所有其他线程,直到第一个线程将静态数据加载到缓存中,并且一旦第一个线程完成将数据加载到缓存中,其他线程应该使用该缓存而不是尝试再次加载。 / p>

    看起来微不足道,但不知何故无法想到任何可以解决这个问题的多线程功能。

    我的代码如下所示:

    somemethod()
    {
      if(cache.Contains(someKey)
      {
        // use cache and do further processing
      }
      else
      {
         cache.add(someKey)
      }
    }
    

2 个答案:

答案 0 :(得分:0)

您可以尝试以下逻辑 1)Thread1 for come并发现该对象不存在于缓存中 2)在此会话Id的缓存中放置一个等待命令对象。该对象告诉任何其他线程等待进一步通知。 3)Thread1从DB中获取数据并将其放回缓存中。 4)Thread1通知其他线程他们可以继续,因为数据现在可用。

答案 1 :(得分:0)

经典补救措施再次竞争条件是相互排斥。锁定是提供此类功能的最简单的解决方案。

public class Cache
{
    private object _locker = new object();
    private SessionDataCollection _cache;

    public SessionData Get(SessionId id)
    {
        lock (_locker)
        {
            if (!Contains(id))
                Fetch(id);

            return Retrieve(id);
        }
    }

    private bool Contains(SessionId id)
    {
        //check if present in _cache
    }

    private void Fetch(SessionId id)
    {
        //get from db and store in _cache
    }

    private SessionData Retrieve(SessionId id)
    {
        //retrvieve from _cache
    }
}