1

我们有一个相当大的 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。

谢谢你的帮助 =)

4

1 回答 1

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)
    {
        // ...
    }
}

我认为这将有助于最大限度地减少您的代码更改。

于 2013-06-07T08:17:33.277 回答