. net多线程:当锁定时间过长时,用日志锁定对象

本文关键字:锁定 对象 日志 多线程 定时间 net | 更新日期: 2023-09-27 17:49:40

在系统中,我们有通过特定参数锁定对象的方法。作为实现,我们有LockManager的Enter方法,它接收锁的键,检查锁对象是否存在于内部字典中,如果不存在,它创建它,然后锁。

我想做的是,为特定的锁设置"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]);
        }
    }
}

现在我想添加一个额外的方法,让我们说LockTimoutHandler(T key),将被调用,如果对象为特定的键被锁定超过X时间

为了做到这一点,我想在"Enter"answers"Exit"方法中添加一些逻辑。当Enter被调用时,某些东西将以某种方式注册以在X时间内运行LockTimoutHandler,当"Exit"被调用时,某些东西将以某种方式未注册

我的问题是我可以用什么来代替?如何安排方法在X时间运行,如果之前发生了Exit,那么删除计划。它必须非常快,因为性能在我们的例子中非常重要。我知道定时器对象…它可以延迟执行方法,但是它的性能足够好吗?我有什么其他的选择来实现这个目标?

注意:为了清楚,我不是在谈论TryEnter。我并不是想抓住对象在特定的时间内无法锁定的情况,我想抓住已经锁定了太长时间的对象。

谢谢!

. net多线程:当锁定时间过长时,用日志锁定对象

我们也有类似的需求,我们是这样解决的:

  • 当锁定时,设置一个计时器到超时,传递一个状态对象,它包含密钥和一个委托,无论你想要:日志,强制解锁,…
  • 当定时器触发时,检查键,如果条目存在,调用delegate
  • 重要:回收定时器(例如,在线程安全队列中),做而不是让它超出作用域。
  • 当您下次需要计时器时,从回收队列中取出一个并操作状态对象-仅在需要时创建一个新的。

这将根据需要保留尽可能多的计时器,但不会更多,并且只会产生一次分配/释放的成本。因为你不能改变定时器的状态对象,你需要改变它的内容。

我认为你可以做得更简单。计时器是一个非常轻量级的对象,我不会试图限制它们的数量。所有的定时器都运行在线程池中的一个特殊线程中,它们真的很便宜。

创建一个计时器字典(如果它将在不同的线程中使用,您可能需要将其更改为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将只执行一次——在指定的超时之后。当item被释放时,从字典中删除timer:

Timer timer;
if (timers.TryGetValue(key, out timer))
{
    timer.Dispose();
    timers.Remove(key);
}