监视器等待缓存,...这是一个好习惯吗?

时间:2016-05-25 06:44:33

标签: c# multithreading caching synchronization data-caching

我刚写了一段代码,然后我发现monitor.wait存在一些问题,迫使我在锁内执行操作,我想现在如果这是保持线程等待的好方法,....

我不确定thread.join是否会完成这项工作,因为我的应用程序中运行了很多线程,并且每个线程都执行特定的工作,它们可能会在时间内终止...

这是我的代码:

public static class TaskManager
{
    private static readonly object UpdateLock = new object();
    private static readonly object WaitLock = new object();

    private static readonly LiaisonDb _db = new LiaisonDb();
    private static List<liaQueue> _liaQueueList = new List<liaQueue>();
    private static DateTime _lastUpdate = new DateTime();

    public static liaQueue GetTask(string sessionType)
    {
        liaQueue task;
        lock (UpdateLock)
        {
            if (_lastUpdate < DateTime.Now.AddSeconds(-5))
            {
                Thread t = new Thread(UpdateCache) {IsBackground = true};
                t.Start();
                lock (WaitLock)
                {
                    Monitor.Wait(WaitLock);
                }

                _lastUpdate = DateTime.Now;
            }
            task = _liaQueueList
                .FirstOrDefault(w => w.Stat == 0
                                     && w.Type != null
                                     || string.Equals(w.Type, sessionType));
        }
        return task;
    }

    private static void UpdateCache()
    {
        try
        {
            _liaQueueList = _db.liaQueue.Where(w => w.Stat == 0).ToList();
        }
        finally
        {
            lock (WaitLock)
            {
                Monitor.Pulse(WaitLock);
            }
        }
    }
}

如你所见,我放了两个锁,其中一个只用于monitor.wait,让线程等待答案......

我想我还必须在刷新缓存时返回null?...

1 个答案:

答案 0 :(得分:2)

来自MSDN

  

如果两个线程正在使用Pulse和Wait进行交互,则可能导致死锁。

所以,不。您的实施不是最佳做法。

在我看来,GetTask应该更新后台线程上的缓存,然后阻止调用线程直到缓存更新,然后根据选择标准返回第一个任务。

由于调用线程将阻塞(等待)缓存更新,我不太了解首先使用后台线程的意义。 如果目的是防止多个调用线程并行更新缓存,请仅使用lock(UpdateLock)语句。

如果您确实想要在后台线程上运行缓存(并等待它),请考虑使用Task库。但我并没有说明问题。

lock (UpdateLock)
{
  if (_lastUpdate < DateTime.Now.AddSeconds(-5)) {
    Task.Run(() => {
      _liaQueueList = _db.liaQueue.Where(w => w.Stat == 0).ToList();
    }).Wait();

    _lastUpdate = DateTime.Now;
  }
}

return _liaQueueList.FirstOrDefault(w => w.Stat == 0 && w.Type != null || string.Equals(w.Type, sessionType));