Блокировка по тайм-ауту
lock
использует этот шаблон
if(Monitor.Enter(lock))
try
{
...
}
finally { Monitor.Exit(lock); } // using this style to reduce post "height"
если мы не хотим ждать бесконечно, мы можем предоставить тайм-аут
if(!Monitor.TryEnter(lock, timeout))
throw new TimeoutException();
try
{
...
}
finally { Monitor.Exit(lock); }
У меня есть сценарий, когда метод должен получить несколько блокировок, прежде чем начать что-либо делать. Это выглядит ужасно:
if(!Monitor.TryEnter(lockA, timeout))
throw new TimeoutException();
try
{
if(!Monitor.TryEnter(lockB, timeout))
throw new TimeoutException();
try
{
if(!Monitor.TryEnter(lockC, timeout))
throw new TimeoutException();
try
{
... // more of such constructions
}
finally { Monitor.Exit(lockC); }
}
finally { Monitor.Exit(lockB); }
}
finally { Monitor.Exit(lockA); }
У него есть проблемы:
выглядит некрасиво (код метода с отступом, представьте, как он будет выглядетьlockZ
), можно решить, поместив код метода в другой метод.
Блокировка происходит синхронно, поэтому наихудший успешный случай может занять немного меньше суммы всех таймаутов.
Есть ли способ улучшить этот тайм-аут?
Я думал создать метод с параметром делегата и блокировкой для достижения чего-то вроде цепочки linq (но также и для параллельной работы блокировок это сложная задача):
Lock(lockA).Lock(lockB).Lock(lockC).Run( () => ...);
Или, может быть, есть другой способ?