C# 这种锁定和管理锁定异常的解决方案有什么问题?
我的目标是在应用程序中实现线程安全功能和异常处理的约定。我对线程管理/多线程的概念比较陌生。我正在使用C# 这种锁定和管理锁定异常的解决方案有什么问题?,c#,multithreading,.net-3.5,locking,thread-safety,C#,Multithreading,.net 3.5,Locking,Thread Safety,我的目标是在应用程序中实现线程安全功能和异常处理的约定。我对线程管理/多线程的概念比较陌生。我正在使用.NET3.5 在阅读本文之后,我编写了以下helper方法来包装我所有锁定的操作,这篇文章是为了回答这个问题而链接的 我的想法是,如果我在应用程序中始终使用此约定,那么编写线程安全代码和处理线程安全代码中的错误将更容易,而不会破坏状态 public static class Locking { private static readonly Dictionary<object,
.NET3.5
在阅读本文之后,我编写了以下helper方法来包装我所有锁定的操作,这篇文章是为了回答这个问题而链接的
我的想法是,如果我在应用程序中始终使用此约定,那么编写线程安全代码和处理线程安全代码中的错误将更容易,而不会破坏状态
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];
}
}
}
下面是一个示例usage类来说明我打算如何使用它
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;
}
}
虽然它看起来可靠,但我有三个顾虑: 1) Invoke()在每个锁定操作上的性能代价可能非常高。 2) 如果操作(方法)需要参数怎么办?需要一个更复杂的解决方案。
3) 腐败现象是否会不断增加?我认为uncorrupt()方法应该在删除对象时遇到问题,而不是将数据设置为false。由于TryLockedAction中的竞争,您的解决方案似乎只增加了复杂性:
if (IsCorrupt(lockObject))
{
exception = new LockingException("Cannot execute locked action on a corrupt object.");
return false;
}
exception = null;
Monitor.Enter(lockObject);
当我们仍在等待监视器时,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
}
}
就我个人而言,我总是倾向于认为手动锁定很难在您单独需要时处理每种情况(因此在通用状态管理解决方案中没有太多需要),并且低级别的工具可以非常节省地使用它
public static class Locking
{
private static readonly Dictionary<object, Exception> CorruptionStateDictionary = new Dictionary<object, Exception>();
private static readonly object CorruptionLock = new object();
public static bool TryLockedAction(object lockObject, Action action, out Exception exception)
{
var lockTaken = false;
exception = null;
try
{
Monitor.Enter(lockObject, ref lockTaken);
if (IsCorrupt(lockObject))
{
exception = new LockingException("Cannot execute locked action on a corrupt object.");
return false;
}
action.Invoke();
}
catch (Exception ex)
{
var corruptionLockTaken = false;
exception = ex;
try
{
Monitor.Enter(CorruptionLock, ref corruptionLockTaken);
if (CorruptionStateDictionary.ContainsKey(lockObject))
{
CorruptionStateDictionary[lockObject] = ex;
}
else
{
CorruptionStateDictionary.Add(lockObject, ex);
}
}
finally
{
if (corruptionLockTaken)
{
Monitor.Exit(CorruptionLock);
}
}
}
finally
{
if (lockTaken)
{
Monitor.Exit(lockObject);
}
}
return exception == null;
}
public static void Uncorrupt(object corruptLockObject)
{
var lockTaken = false;
try
{
Monitor.Enter(CorruptionLock, ref lockTaken);
if (IsCorrupt(corruptLockObject))
{
{ CorruptionStateDictionary.Remove(corruptLockObject); }
}
}
finally
{
if (lockTaken)
{
Monitor.Exit(CorruptionLock);
}
}
}
public static bool IsCorrupt(object lockObject)
{
Exception ex = null;
return IsCorrupt(lockObject, out ex);
}
public static bool IsCorrupt(object lockObject, out Exception ex)
{
var lockTaken = false;
ex = null;
try
{
Monitor.Enter(CorruptionLock, ref lockTaken);
if (CorruptionStateDictionary.ContainsKey(lockObject))
{
ex = CorruptionStateDictionary[lockObject];
}
return CorruptionStateDictionary.ContainsKey(lockObject);
}
finally
{
if (lockTaken)
{
Monitor.Exit(CorruptionLock);
}
}
}
}
公共静态类锁定
{
私有静态只读字典损坏StateDictionary=new Dictionary();
私有静态只读对象损坏锁=新对象();
公共静态bool TryLockedAction(对象锁定对象、操作操作、输出异常)
{
var-locktake=false;
异常=空;
尝试
{
监视器。输入(锁定对象,参考锁定);
if(IsCorrupt(lockObject))
{
exception=new LockingException(“无法对损坏的对象执行锁定操作”);
返回false;
}
action.Invoke();
}
捕获(例外情况除外)
{
var CorruptionLockTake=false;
例外=例外;
尝试
{
Monitor.Enter(CorruptionLock,ref CorruptionLock take);
if(CorruptionStateDictionary.ContainsKey(lockObject))
{
CorruptionStateDictionary[lockObject]=ex;
}
其他的
{
CorruptionStateDictionary.Add(lockObject,ex);
}
}
最后
{
如果(发生腐败)
{
监控。退出(腐蚀锁);
}
}
}
最后
{
如果(已锁定)
{
监视器。退出(锁定对象);
}
}
返回异常==null;
}
公共静态无效未损坏(对象损坏锁定对象)
{
var-locktake=false;
尝试
{
监控。输入(腐蚀锁,参考锁);
if(IsCorrupt(corruptLockObject))
{
{CorruptionStateDictionary.Remove(corruptLockObject);}
}
}
最后
{
如果(已锁定)
{
监控。退出(腐蚀锁);
}
}
}
公共静态bool IsCorrupt(对象锁定对象)
{
异常ex=null;
返回IsCorrupt(lockObject,out-ex);
}
公共静态bool IsCorrupt(对象锁定对象,out异常ex)
{
var-locktake=false;
ex=null;
尝试
{
监控。输入(腐蚀锁,参考锁);
if(CorruptionStateDictionary.ContainsKey(lockObject))
{
ex=CorruptionStateDictionary[lockObject];
}
返回CorruptionStateDictionary.ContainsKey(lockObject);
}
最后
{
如果(已锁定)
{
监控。退出(腐蚀锁);
}
}
}
}
我建议的方法是使用一个带有“inDangerState”字段的锁状态管理器对象。需要访问受保护资源的应用程序通过使用锁管理器对象获取锁来启动;管理器将代表应用程序获取锁,并检查inDangerState标志。如果设置好了,经理将
public static class Locking
{
private static readonly Dictionary<object, Exception> CorruptionStateDictionary = new Dictionary<object, Exception>();
private static readonly object CorruptionLock = new object();
public static bool TryLockedAction(object lockObject, Action action, out Exception exception)
{
var lockTaken = false;
exception = null;
try
{
Monitor.Enter(lockObject, ref lockTaken);
if (IsCorrupt(lockObject))
{
exception = new LockingException("Cannot execute locked action on a corrupt object.");
return false;
}
action.Invoke();
}
catch (Exception ex)
{
var corruptionLockTaken = false;
exception = ex;
try
{
Monitor.Enter(CorruptionLock, ref corruptionLockTaken);
if (CorruptionStateDictionary.ContainsKey(lockObject))
{
CorruptionStateDictionary[lockObject] = ex;
}
else
{
CorruptionStateDictionary.Add(lockObject, ex);
}
}
finally
{
if (corruptionLockTaken)
{
Monitor.Exit(CorruptionLock);
}
}
}
finally
{
if (lockTaken)
{
Monitor.Exit(lockObject);
}
}
return exception == null;
}
public static void Uncorrupt(object corruptLockObject)
{
var lockTaken = false;
try
{
Monitor.Enter(CorruptionLock, ref lockTaken);
if (IsCorrupt(corruptLockObject))
{
{ CorruptionStateDictionary.Remove(corruptLockObject); }
}
}
finally
{
if (lockTaken)
{
Monitor.Exit(CorruptionLock);
}
}
}
public static bool IsCorrupt(object lockObject)
{
Exception ex = null;
return IsCorrupt(lockObject, out ex);
}
public static bool IsCorrupt(object lockObject, out Exception ex)
{
var lockTaken = false;
ex = null;
try
{
Monitor.Enter(CorruptionLock, ref lockTaken);
if (CorruptionStateDictionary.ContainsKey(lockObject))
{
ex = CorruptionStateDictionary[lockObject];
}
return CorruptionStateDictionary.ContainsKey(lockObject);
}
finally
{
if (lockTaken)
{
Monitor.Exit(CorruptionLock);
}
}
}
}