基于参数锁定

时间:2011-06-23 15:53:19

标签: c# .net concurrency

假设我有这个方法:

void Foo(int bar)
{
    // do stuff
}

以下是我希望Foo拥有的行为:

  1. 如果主题1 调用Foo(1)主题2 调用Foo(2),则两个主题都可以同时运行。

    < / LI>
  2. 如果主题1 调用Foo(1)主题2 调用Foo(1),则两个主题都无法运行同时进行。

  3. .net中是否有一种良好的,标准的方式来指定这种行为?我有一个使用对象字典锁定的解决方案,但这感觉有点混乱。

4 个答案:

答案 0 :(得分:8)

使用为不同参数提供不同锁定对象的字典。在实例化基础对象时设置字典(或静态地,如果适用):

var locks = new Dictionary<int, object>() {
    {1, new Object()},
    {2, new Object()},
    …
};

然后在你的方法中使用它:

void Foo(int bar) {
    lock (locks[bar]) {
        …
    }
}

我不会说这个解决方案很混乱,恰恰相反:提供一个精确的锁粒度是值得称道的,因为值的类型锁在.NET中不起作用,所以有一个映射是显而易见的解决方案。

但请注意:只要字典未被同时修改和读取,上述内容才有效。因此,最好在设置后将字典视为只读。

答案 1 :(得分:3)

底线:您无法锁定值类型。

您正在使用的词典是我能想到的最佳方法。它是kludgey,但它确实有效。

就个人而言,我会寻求一种不需要锁定的架构解决方案,但我对你的系统知之甚少,无法给你指点。

答案 2 :(得分:0)

使用Dictionary是不够的,你应该使用&#34; ConcurrentDictionary&#34;或实现支持多线程访问的数据结构。

答案 3 :(得分:-2)

创建词典&lt;&gt;所以你可以锁定一个值似乎有点矫枉过正。我使用字符串工作了。有人(例如Jon Skeet)不喜欢这种方法(并且有正当理由 - 请参阅此帖:Is it OK to use a string as a lock object?

但我有办法减轻这些顾虑:动态实习字符串并将其与唯一标识符结合起来。

// you should insert your own guid here
string lockIdentifier = "a8ef3042-e866-4667-8673-6e2268d5ab8e";
public void Foo(int bar)
{
    lock (string.Intern(string.Format("{0}-{1}", lockIdentifier, bar)))
    {
        // do stuff
    }
}

不同的值存储在字符串实习池(跨越AppDomain边界)中。将lockIdentifier添加到字符串可确保字符串不会与其他应用程序中使用的实际字符串冲突,这意味着锁定只会在您自己的应用程序中生效。

因此,实习池将返回对实习字符串的引用 - 这可以锁定。