2

システムには、特定のパラメータによってオブジェクトをロックするメソッドがあります。実装として、ロックのキーを受け取り、ロックオブジェクトが内部ディクショナリに存在するかどうかを確認するEnterメソッドを備えたLockManagerがあります。存在しない場合は、それを作成してからロックします。

私がやりたいのは、特定のロックに「X予想時間」を設定することです。オブジェクトがX時間以上ロックされた場合は、ログにメッセージを書き込みます。

以下は私のロックマネージャーのソースコードです。

public class MyLockManager<T>
{
    protected Dictionary<T, object> LockDictionary { get; private set; }

    public MyLockManager()
    {
        LockDictionary = new Dictionary<T, object>();
    }

    /// <summary>
    /// Enters a lock on the key.
    /// </summary>
    /// <param name="key">The key to lock.</param>
    public virtual void Enter(T key)
    {
        if (!LockDictionary.ContainsKey(key))
        {
            lock (LockDictionary)
            {
                if (!LockDictionary.ContainsKey(key))
                {
                    LockDictionary.Add(key, new object());
                }
            }
        }

        object lockObj = LockDictionary[key];
        Monitor.Enter(lockObj);
    }

    /// <summary>
    /// Releases the lock on the key.
    /// </summary>
    /// <param name="key">The key to release.</param>
    public virtual void Exit(T key)
    {
        if (LockDictionary.ContainsKey(key))
        {
            Monitor.Exit(LockDictionary[key]);
        }
    }
}

次に、特定のキーのオブジェクトがX時間以上ロックされた場合に呼び出される、追加のメソッド、たとえばLockTimoutHandler(Tキー)を追加します。

それを行うために、「Enter」メソッドと「Exit」メソッドにロジックを追加したいと思います。Enterが呼び出されると、X時間でLockTimoutHandlerを実行するために何かが登録され、 "Exit"が呼び出されると、その何かが何らかの形で登録解除されます。

私の質問は、その代わりに何を使用できるかということです。X時間で実行するようにメソッドをスケジュールする方法と、Exitが以前に発生した場合は、スケジュールを削除します。私たちの場合、パフォーマンスが非常に重要であるため、非常に高速である必要があります。Timerオブジェクトについて知っています...メソッドを遅延して実行できますが、パフォーマンスは十分ですか?それを達成するために必要な追加のオプションは何ですか?

:明確にするために、私はTryEnterについて話していません。オブジェクトを特定の時間ロックできない場合をキャッチしようとはしていません。すでにロックされているオブジェクトをキャッチしたいのです。

ありがとう!

4

2 に答える 2

2

同様の要件があり、次のように解決しました。

  • ロックするときは、タイマーをタイムアウトに設定して、キーとデリゲートを含む状態オブジェクトを渡します。ロギング、強制ロック解除など、ユースケースに必要なものは何でも
  • タイマーが起動したら、キーを確認し、エントリが存在する場合はデリゲートを呼び出します
  • 重要:タイマー (スレッドセーフ キューの eq) をリサイクルし、範囲外にしないでください。
  • 次にタイマーが必要になったら、リサイクル キューから 1 つ取り出して状態オブジェクトを操作します。必要な場合にのみ、新しいタイマーを作成してください。

これにより、必要な数のタイマーが保持されますが、それ以上は保持されず、割り当て/割り当て解除のコストが発生するのは 1 回だけです。タイマーの状態オブジェクトは変更できないため、内容を変更する必要があります。

于 2012-12-25T12:15:23.103 に答える
1

もっと簡単にできると思います。タイマーは非常に軽量なオブジェクトであり、そのカウントを制限しようとしても無駄ではありません。すべてのタイマーは、スレッドプールの特別なスレッドで実行されており、非常に安価です。

タイマーの辞書を作成するだけです(別のスレッドから使​​用する場合は、次のように変更することをお勧めしますConcurrentDictionary

var timers = new Dictionary<T, Timer>();

リストにアイテムを追加するときは、次のコードを使用してタイムアウトを設定します。

var timer = new Timer(o => LogMessage("key {0} is being held too long", key));
timer.Change(timeout, Timeout.Infinite);
timers.Add(key, timer);

タイマーは、指定されたタイムアウト後に一度だけ実行されることに注意してください。そして、アイテムが解放されたら、辞書からタイマーを削除するだけです:

Timer timer;
if (timers.TryGetValue(key, out timer))
{
    timer.Dispose();
    timers.Remove(key);
}
于 2012-12-25T13:09:09.570 に答える