2012-12-25 56 views
2

在系统中,我们有通过特定参数锁定对象的方法。 作为实现,我们使用LockManager和Enter方法接收锁的密钥,检查锁对象是否存在于内部字典中,如果不存在,它会创建它并锁定。.NET多线程:锁定对象时锁定了很多时间的日志

我想要做的是为特定的锁定设置“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键)将被调用,如果特定的键对象被锁定超过X时间。

为了做到这一点,我想为“Enter”和“Exit”方法添加一些逻辑。当输入一个称为,东西也会莫名其妙地被注册运行在X时间LockTimoutHandler,并在“退出”之称,是东西会以某种未注册

我的问题是我可以用来代替东西?如何安排方法在X时间内运行,如果之前出现过,则请删除计划。它必须非常快速,因为在我们的情况下,性能非常重要。我知道Timer对象...它可以以延迟的方式执行方法,但它的性能足够好吗?我有什么额外的选择来实现呢?

注意:只是要清楚,我不是在谈论TryEnter。我不想在特定时间内无法锁定对象的情况下捕捉对象,我想捕获已锁定时间过长的对象。

谢谢!

+1

您的输入法不是线程安全的。你可能会在不同的线程中同时阅读和写字典。这可能会导致您的应用程序发生死锁。 – pstrjds

回答

2

我们也有类似的rquirement,解决这样说:

  • 锁定时,设置一个定时器超时传递一个状态对象,包含任何你想要的钥匙和代表:日志,力-unlock,......必要的操作为您的使用情况
  • 当计时器火灾,检查关键,如果条目存在电话委托
  • 重要:回收定时器(在线程队列当量),做不是让它超出范围。
  • 当你下一次需要一个计时器时,从循环队列中取出一个并操作状态对象 - 只在需要时才创建一个新对象。

这样可以保持尽可能多的计时器,但不会再发生,只会产生一次分配/取消分配的成本。由于您无法更改计时器的状态对象,因此您需要更改其内容。

+0

我如何“清除”计时器?我的意思是如果对象快速解锁,我不想调用该方法。 –

+0

让计时器开火吧!它会查找字典中的关键字,但找不到它,从而什么都不做。或者,由于您不在锁字典中存储任何内容,因此您也可以在其中存储对定时器的引用,并使用它将其设置为无穷大。 –

+0

好吧,它看起来像可行的解决方案,但如何计时器性能和线程消费?我们有高负载的应用程序处理不同的请求,恐怕计时器会降低我们的性能太多。 –

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); 
}