65.9K
CodeProject 正在变化。 阅读更多。
Home

基本的命名锁类

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.29/5 (4投票s)

2008 年 1 月 30 日

BSD

2分钟阅读

viewsIcon

34583

downloadIcon

185

这是一个用于获取命名锁的实用类。

引言

我遇到了一些需要同步特定“名称”的情况。我参与的一个应用程序大量使用 Lucene.NET;每个页面显示几个查询的结果。同时对 Lucene 运行多个相同的查询没有太大意义,所以我为每个查询生成一个键,针对该键进行加锁,并让第一个线程执行实际操作,而其他线程则悠闲地喝咖啡。

使用代码

使用这个类非常简单。创建一个新的 NamedLock<string> 实例,然后在 using 语句中调用 Lock 函数。

NamedLock<string> locker = new NamedLock<string>();
var url = "http://services.digg.com...";
using (locker.Lock(url))
{
    //Do something synchronized
    var xml = new XmlDocument();
    xml.Load(url);
}

关注点

请查看类本身。它相对较小,包含三部分:

  • 包含 LockUnlock 函数的主要类
  • 实现 IDisposable 的内部 Token
  • 内部 ReferenceCount

NamedLock 非常简单。它包含一个 Dictionary<T, ReferenceCount> 来跟踪当前锁定的名称,并提供用于获取和释放锁的实用函数。Lock 的代码如下:

public IDisposable Lock(T name, int timeout)
{
    Monitor.Enter(lockCollection);
    ReferenceCount obj = null;
    lockCollection.TryGetValue(name, out obj);
    if (obj == null)
    {
        obj = new ReferenceCount();
        Monitor.Enter(obj);
        lockCollection.Add(name, obj);
        Monitor.Exit(lockCollection);
    }
    else
    {
        obj.AddRef();
        Monitor.Exit(lockCollection);
        if (!Monitor.TryEnter(obj, timeout))
        {
            throw new TimeoutException(
                string.Format(
                "Timeout while waiting for lock on {0}", 
                name)
                );
        }
    }

    return new Token<T>(this, name);
}

此函数锁定 lockCollection,检查是否存在具有相同名称的现有锁,如果它是第一个,则添加一个,然后锁定并返回一个令牌。它使用 Monitor.Enter 而不是简单的 lock 语句,原因很好:您会注意到,如果集合中没有当前锁,我们实际上会在释放集合上的锁之前锁定同步对象(命名为 obj)。如果锁存在于集合中,我们会递增引用计数器,释放集合锁,然后锁定同步对象。这样做可以避免对锁集合的死锁(不妙)。

Unlock 函数也很简单明了

public void Unlock(T name)
{
    lock (lockCollection)
    {
        ReferenceCount obj = null;
        lockCollection.TryGetValue(name, out obj);
        if (obj != null)
        {
            Monitor.Exit(obj);
            if (0 == obj.Release())
            {
                lockCollection.Remove(name);
            }
        }
    }
}

它锁定 lockCollection,获取同步对象,释放命名锁,然后在没有其他线程持有对其引用时删除同步对象。这段代码更直接,因为我们不必做任何花招来避免锁集合上的死锁。

令牌类非常简单,我甚至懒得把它粘贴在这里。它接受对父级 NamedLock 的引用,然后在释放时调用 parent.Unlock(name)

历史

© . All rights reserved.