Монитор Ждите кеширования, это хорошая практика?

Я просто написал код, а затем обнаружил, что есть проблема с 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, продолжайте поток, ожидая ответа...

я думаю, что я также должен вернуть ноль, пока кэш обновляется?...

1 ответ

Решение

Из MSDN

Если два потока используют Pulse и Wait для взаимодействия, это может привести к тупику.

Так что нет. Ваша реализация не будет лучшей практикой.

Мне кажется, что GetTask должен обновлять кэш в фоновом потоке, затем блокировать вызывающий поток до тех пор, пока кэш не будет обновлен, а затем вернуть первую задачу в соответствии с выбранными критериями.

Поскольку вызывающий поток будет блокировать (ждать) обновление кэша, я не совсем понимаю смысл использования фонового потока в первую очередь. Если цель состоит в том, чтобы предотвратить одновременное обновление кэша несколькими вызывающими потоками, используйте только оператор блокировки (UpdateLock).

Если вы все равно хотите запустить кэш в фоновом потоке (и дождаться его), рассмотрите возможность использования библиотеки задач. Но я не вижу смысла в этом.

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));
Другие вопросы по тегам