Что не так с этим решением для блокировки и управления заблокированными исключениями?

Моя цель - соглашение о поточно-ориентированной функциональности и обработке исключений в моем приложении. Я относительно новичок в концепции управления потоками / многопоточности. Я использую .NET 3.5

Я написал следующий вспомогательный метод, чтобы обернуть все мои заблокированные действия после прочтения этой статьи http://blogs.msdn.com/b/ericlippert/archive/2009/03 /06/locks-and-exceptions-do-not-mix.aspx, ссылка на которую была дана в ответ на этот вопрос Монитор против блокировки .

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

public static class Locking
{

    private static readonly Dictionary CorruptionStateDictionary = new Dictionary(); 
    private static readonly object CorruptionLock = new object();

    public static bool TryLockedAction(object lockObject, Action action, out Exception exception)
    {
        if (IsCorrupt(lockObject))
        {
            exception = new LockingException("Cannot execute locked action on a corrupt object.");
            return false;
        }
        exception = null;
        Monitor.Enter(lockObject);
        try
        {
            action.Invoke();
        }
        catch (Exception ex)
        {
            exception = ex;
        }
        finally
        {
            lock (CorruptionLock)   // I don't want to release the lockObject until its corruption-state is updated.
                                    // As long as the calling class locks the lockObject via TryLockedAction(), this should work
            {
                Monitor.Exit(lockObject);
                if (exception != null)
                {   
                    if (CorruptionStateDictionary.ContainsKey(lockObject))
                    {
                        CorruptionStateDictionary[lockObject] = true;
                    }
                    else
                    {
                        CorruptionStateDictionary.Add(lockObject, true);
                    }
                }
            }
        }
        return exception == null;
    }

    public static void Uncorrupt(object corruptLockObject)
    {
        if (IsCorrupt(corruptLockObject))
        {
            lock (CorruptionLock)
            {
                CorruptionStateDictionary[corruptLockObject] = false;
            }
        }
        else
        {
            if(!CorruptionStateDictionary.ContainsKey(corruptLockObject))
            {
                throw new LockingException("Uncorrupt() is not valid on object that have not been corrupted."); 
            }
            else
            {
                //  The object has previously been uncorrupted.
                //  My thought is to ignore the call.
            }
        }
    }

    public static bool IsCorrupt(object lockObject)
    {
        lock(CorruptionLock)
        {
            return CorruptionStateDictionary.ContainsKey(lockObject) && CorruptionStateDictionary[lockObject];
        }
    }


}

Я использую класс LockingException для удобства отладки.

    public class LockingException : Exception
    {
        public LockingException(string message) : base(message) { }
    }

Вот пример класса использования, чтобы показать, как я собираюсь его использовать.

public class ExampleUsage
{
    private readonly object ExampleLock = new object();

    public void ExecuteLockedMethod()
    {
        Exception exception;
        bool valid = Locking.TryLockedAction(ExampleLock, ExecuteMethod, out exception);
        if (!valid)
        {
            bool revalidated = EnsureValidState();
            if (revalidated)
            {
                Locking.Uncorrupt(ExampleLock);
            }
        }
    }

    private void ExecuteMethod()
    {
        //does something, maybe throws an exception

    }

    public bool EnsureValidState()
    {
        // code to make sure the state is valid
        // if there is an exception returns false,

        return true;
    }
}

6
задан Community 23 May 2017 в 11:46
поделиться