基于参数锁定

假设我有这个方法:

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

这是我想让Foo拥有的行为:

  1. 如果线程1调用Foo(1)线程2调用Foo(2) ,则两个线程可以并发运行。

  2. 如果线程1调用Foo(1)线程2调用Foo(1) ,则两个线程不能同时运行。

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

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

 var locks = new Dictionary() { {1, new Object()}, {2, new Object()}, … }; 

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

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

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

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

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

你正在使用的词典是我能想到的最佳方法。 它是kludgey,但它的工作原理。

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

使用Dictionary是不够的,您应该使用“ConcurrentDictionary”或实现支持multithreading访问的数据结构。

创建一个字典<>,以便你可以锁定一个值似乎有点矫枉过正。 我使用字符串工作了。 有人(例如Jon Skeet)不喜欢这种方法(并且有正当理由 – 请参阅这篇文章: 使用字符串作为锁定对象是否可以? )

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

 // 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添加到字符串可确保字符串不会与其他应用程序中使用的实际字符串冲突,这意味着锁只会在您自己的应用程序中生效。

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