.NET Multithreading: Lock object with log when locked for to much time

那年仲夏 提交于 2019-12-14 02:19:11

问题


In system we have methods that lock an object by specific params. As implementation, we have LockManager with Enter method that receives a key for a lock, check if lock object exists in internal dictionary, if not, it creates it and then locks.

What I want to do, is to set "X expected time" for specific lock, and if an object was locked for more that X time, I want to write a message to our log.

Below is a source code for my lock manager:

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

Now I want to add an additional method, lets say LockTimoutHandler(T key) that will be called, if object for specific key was locked for more than X time.

In order to do it, I want to add some logic to "Enter" and "Exit" methods. When Enter called, something will be somehow registered to run the LockTimoutHandler in X time, and when "Exit" called, that something will be somehow unregistered.

My question is what I can use instead of that something? How I can schedule the method to run in X time and if Exit occurred before, so remove the schedule. It must be very fast, since performance is very important in our case. I know about Timer object...it can execute method in delayed manner, but is it's performance good enough? What additional options I have to achieve that?

NOTE: Just to be clear, I am not talking about TryEnter. I am not trying to catch the case when the object can not be locked for specific amount of time, I want to catch objects that already locked for too much time.

Thanks!


回答1:


We had a similar rquirement and solved it this way:

  • When locking, set a timer to the timeout passing it a state object, that contains the key and a delegate whatever you desire: Logging, force-unlock, ... whatever is needed for your use case
  • When the timer fires, check for the key, if entry exists call delegate
  • Important: recycle the timer (e.q. in a threadsafe queue), do not let it go out of scope.
  • When you next need a timer, take one out of the recycle queue and manipulate the state object - only create a new one if you need to.

This will keep as many timers around as necessary, but no more and will incur the cost of allocation/deallocation only once. Since you can't change the timer's state object, you need to change its contents.




回答2:


I think you can do it simpler. Timer is very light weight object and I wouldn't bare with trying to limit their count. All timers are running in a special thread from threadpool and they are really cheap.

Just create a dictionary of timers (if it will be used from different threads you may want to change it to ConcurrentDictionary:

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

When adding item to your list use this code to setup timeout:

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

Note that timer will be executed only once -- after specified timeout. And when item is released just remove timer from the dictionary:

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


来源:https://stackoverflow.com/questions/14030491/net-multithreading-lock-object-with-log-when-locked-for-to-much-time

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!