mercredi 22 juin 2016

Locking with timeout pattern

lock uses this pattern

if(Monitor.Enter(lock))
    try
    {
        ...
    }
    finally { Monitor.Exit(lock); } // using this style to reduce post "height"

if we don't want to wait infinite we can provide timeout

if(!Monitor.TryEnter(lock, timeout))
    throw new TimeoutException();
try
{
    ...
}
finally { Monitor.Exit(lock); }

I have scenario when method has to obtain multiple locks before it start doing anything. This looks awful:

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); }

It has problems:

  • looks ugly (the method code is indented, imagine how it will looks for lockZ), can be solved by putting method code into another method.

  • locking occurs synchronously, so the worst successful case may take time slightly less than a sum of all timeouts.

Is there a way to improve this timeout pattern?

I was thinking to make a method with delegate parameter and lock to achieve something like linq chaining (but to also run locks in parallel, this is a challenge):

Lock(lockA).Lock(lockB).Lock(lockC).Run( () => ...);

Or perhaps there is another way?

Aucun commentaire:

Enregistrer un commentaire