将字符串用作锁定对象是否可以?

Zai*_*sud 42 .net c# multithreading locking .net-4.0

我需要在一组有限的字符串的基础上在一个区域中创建一个临界区.我希望为同一个字符串实例共享锁(有点类似于String.Intern方法).

我正在考虑以下实施:

public class Foo
{
    private readonly string _s;
    private static readonly HashSet<string> _locks = new HashSet<string>();

    public Foo(string s)
    {
        _s = s;
        _locks.Add(s);
    }

    public void LockMethod()
    {
        lock(_locks.Single(l => l == _s))
        {
            ...
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这种方法有什么问题吗?以这种方式锁定字符串对象是否可以,并且在使用时是否存在任何线程安全问题HashSet<string>

例如,创建一个Dictionary<string, object>为每个字符串实例创建一个新的锁对象是否更好?


最终实施

根据我的建议,我采用了以下实现:

public class Foo
{
    private readonly string _s;
    private static readonly ConcurrentDictionary<string, object> _locks = new ConcurrentDictionary<string, object>();

    public Foo(string s)
    {
        _s = s;
    }

    public void LockMethod()
    {
        lock(_locks.GetOrAdd(_s, _ => new object()))
        {
            ...
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Hen*_*man 25

不鼓励锁定字符串,主要原因是(因为字符串实习)一些其他代码可能会在不知道这一点的情况下锁定同一个字符串实例.创造陷入僵局的可能性.

现在,在大多数具体情况下,这可能是一个牵强附会的场景.这更像是图书馆的一般规则.

但另一方面,字符串的感知益处是什么?

所以,要点:

这种方法有什么问题吗?

是的,但主要是理论上的.

以这种方式锁定字符串对象是否可以,并且在使用HashSet时是否存在任何线程安全问题?

HashSet<>只要线程唯一同时读取不参与线程安全的.

例如,创建一个为每个字符串实例创建新锁定对象的Dictionary更好吗?

是.只是为了安全起见.在大型系统中,避免死锁的主要目的是使锁定对象尽可能保持本地和私有.只有有限数量的代码才能访问它们.


Jon*_*eet 24

我个人说,这是一个非常糟糕的主意.这不是字符串的用途.

(我个人不喜欢这样一个事实,即每个物体都有一个显示器,但这是一个稍微不同的问题.)

如果你想要一个代表一个可以在不同实例之间共享的锁的对象,为什么不为它创建一个特定的类型呢?您可以很容易地为锁定一个名称以进行诊断,但锁定实际上不是字符串的用途.像这样的东西:

public sealed class Lock
{
    private readonly string name;

    public string Name { get { return name; } }

    public Lock(string name)
    {
        if (name == null)
        {
            throw new ArgumentNullException("name");
        }
        this.name = name;
    }
}
Run Code Online (Sandbox Code Playgroud)

考虑到字符串有时被实现的方式,有时候没有(通过简单的检查偶尔难以识别的方式),你很容易就会意外地分享你不想要它们的共享锁.

  • @Alex:不,我真的不这么认为 - 你基本上有锁的全局命名空间......你怎么知道其他代码会用到什么?是的,实习将确保您获得该名称的锁定,但确保只有适当的代码使用它的严格性在哪里? (2认同)

Bri*_*sen 6

锁定字符串可能会有问题,因为实习字符串本质上是全局的.

Interned字符串是每个进程,因此它们甚至可以在不同的AppDomain之间共享.类型对象也是如此(所以不要锁定typeof(x)).

  • 有时每个进程锁定变量是您正在寻找的; p (2认同)