锁定和管理锁定异常的解决方案有什么问题?

sma*_*man 6 c# multithreading locking thread-safety .net-3.5

我的目标是在我的应用程序中使用线程安全功能和异常处理的约定.我对线程管理/多线程的概念比较陌生.我在用.NET 3.5

我写了下面的辅助方法看完这篇文章后总结我的所有锁定动作http://blogs.msdn.com/b/ericlippert/archive/2009/03/06/locks-and-exceptions-do-not-mix. aspx,它是针对这个问题而链接的,Monitor vs lock.

我的想法是,如果我在我的应用程序中一致地使用此约定,那么编写线程安全代码并在线程安全代码中处理错误将更容易,而不会破坏状态.

public static class Locking
{

    private static readonly Dictionary<object,bool> CorruptionStateDictionary = new Dictionary<object, bool>(); 
    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];
        }
    }


}
Run Code Online (Sandbox Code Playgroud)

我使用LockingException类来简化调试.

    public class LockingException : Exception
    {
        public LockingException(string message) : base(message) { }
    }
Run Code Online (Sandbox Code Playgroud)

这是一个示例用法类,用于说明我打算如何使用它.

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

Kon*_*hin 7

由于TryLockedAction中的竞争,您的解决方案似乎只增加了复杂性:


        if (IsCorrupt(lockObject))
        {
            exception = new LockingException("Cannot execute locked action on a corrupt object.");
            return false;
        }
        exception = null;
        Monitor.Enter(lockObject);

当我们仍在等待Monitor.Enter时,lockObject可能会"损坏",因此没有保护.

我不确定你想要实现什么行为,但可能有助于分离锁定和状态管理:


class StateManager
{
    public bool IsCorrupted
    {
        get;
        set;
    }

    public void Execute(Action body, Func fixState)
    {
        if (this.IsCorrupted)
        {
            // use some Exception-derived class here.
            throw new Exception("Cannot execute action on a corrupted object.");
        }

        try
        {
            body();
        }
        catch (Exception)
        {
            this.IsCorrupted = true;
            if (fixState())
            {
                this.IsCorrupted = false;
            }

            throw;
        }
    }
}

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

    public void ExecuteLockedMethod()
    {
        lock (ExampleLock)
        {
            stateManager.Execute(ExecuteMethod, EnsureValidState);
        }
    }

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

另外,据我所知,文章的重点是状态管理在并发存在时更难.但是,它仍然只是您的对象状态正确性问题,与锁定正交,可能您需要使用完全不同的方法来确保正确性.例如,不是使用锁定的代码区域更改某些复杂状态,而是创建一个新的,如果成功,只需在单个简单的引用赋值中切换到新状态:


public class ExampleUsage
{
    private ExampleUsageState state = new ExampleUsageState();

    public void ExecuteLockedMethod()
    {
        var newState = this.state.ExecuteMethod();
        this.state = newState;
    }
}

public class ExampleUsageState
{
    public ExampleUsageState ExecuteMethod()
    {
        //does something, maybe throws an exception
    }
}

就个人而言,我总是倾向于认为手动锁定足以在需要时单独处理每个案例(因此在通用状态管理解决方案中没有太多需要)和低水平的工具,以便真正谨慎地使用它.