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機能はステートメントを厳密にモデル化するため、 usingIDisposable を実装するクラスでロジックをラップすることをお勧めします。

クラスのコンストラクターはロックの取得を試み、ロックの取得に失敗した場合は、例外をスローするかログに記録することができます。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 に答える