我们有一个非常大的winforms桌面应用程序。我们的应用程序每隔一段时间运行一次就陷入僵局,我们不确定这是怎么发生的。
我们知道这是由锁定操作引起的。所以我们有很多这样的代码部分:
lock (_someObj)
DoThreadSaveOperation();
我们的方法是能够检测到我们想要将所有锁定操作转换为这样的锁定操作导致的死锁:
bool lockTaken = false;
var temp = _someObj;
try {
System.Threading.Monitor.TryEnter(temp, 1000, ref lockTaken);
if (!lockTaken)
{
// log "can't get lock, maybe deadlock, print stacktrace
}
DoThreadSaveOperation();
}
finally {
System.Threading.Monitor.Exit(temp);
}
这种“锁定服务”应处于中心位置。问题是它必须像这样调用:
LockService.RunWithLock(object objToLock, Action methodToRun);
这意味着我们必须为锁定后执行的每个语句创建一个委托函数。
由于这会进行大量的重构,我想如果你们对这个问题有更好/更好的想法,我会尝试使用stackoverflow,并征求你的意见。
谢谢你的帮助=)
答案 0 :(得分:0)
由于现有的lock
功能非常接近using
语句的模型,我建议您将逻辑包装在实现IDisposable的类中。
类的构造函数会尝试获取锁,如果它无法获得锁,您可以抛出异常或记录它。 Dispose()方法将释放锁。
您可以在using
语句中使用它,以便在异常情况下保持健壮。
这样的事情:
public sealed class Locker: IDisposable
{
readonly object _lockObject;
readonly bool _wasLockAcquired;
public Locker(object lockObject, TimeSpan timeout)
{
_lockObject = lockObject;
Monitor.TryEnter(_lockObject, timeout, ref _wasLockAcquired);
// Throw if lock wasn't acquired?
}
public bool WasLockAquired
{
get
{
return _wasLockAcquired;
}
}
public void Dispose()
{
if (_wasLockAcquired)
Monitor.Exit(_lockObject);
}
}
您可以这样使用:
using (var locker = new Locker(someObj, TimeSpan.FromSeconds(1)))
{
if (locker.WasLockAquired)
{
// ...
}
}
我认为这有助于最大限度地减少代码更改。