【问题标题】:Locking based on parameters基于参数的锁定
【发布时间】:2011-06-23 15:53:19
【问题描述】:

假设我有这个方法:

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

这是我希望Foo 具有的行为:

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

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

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

【问题讨论】:

  • 在完成阅读您的问题之前我说:我会使用字典... :)

标签: c# .net concurrency


【解决方案1】:

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

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

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

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

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

但请注意:上述方法仅适用于字典未同时修改和读取的情况。因此,最好在设置字典后将其视为只读。

【讨论】:

【解决方案2】:

底线:您不能锁定值类型。

您使用的字典是我能想到的最佳方法。这很笨拙,但很有效。

就个人而言,我会寻求一种无需锁定的架构解决方案,但我对您的系统了解得不够多,无法在此处为您提供指点。

【讨论】:

    【解决方案3】:

    使用字典还不够,应该使用“ConcurrentDictionary”或者实现支持多线程访问的数据结构。

    【讨论】:

    • 我很想知道为什么这个答案被否决了。它表明它是错误的,但它是错误的吗?听起来很合理。
    【解决方案4】:

    创建一个字典 以便您可以锁定一个值对我来说似乎有点过头了。我用一个字符串得到了这个工作。有些人(例如 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 可以确保字符串不会与其他应用程序中使用的 interned 字符串冲突,这意味着锁只会在您自己的应用程序中生效。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-22
      • 1970-01-01
      • 2022-06-10
      • 1970-01-01
      相关资源
      最近更新 更多