【问题标题】:Lock dictionary within same thread在同一线程中锁定字典
【发布时间】:2023-03-12 20:22:01
【问题描述】:

我有一个函数,它根据键(名称)返回字典中的条目,如果它不存在,则返回一个新创建的条目。

我的问题是“双锁”:SomeFunction 锁定 _dictionary,检查密钥是否存在,然后调用一个也锁定同一个字典的函数,它似乎有效,但我不确定是否这种方法存在潜在问题。

public Machine SomeFunction(string name) 
{
    lock (_dictionary)
    {
        if (!_dictionary.ContainsKey(name))
                    return CreateMachine(name);
        return _dictionary[name];
    }
}


private Machine CreateMachine(string name)
{
    MachineSetup ms = new Machine(name);
    lock(_dictionary)
    {
        _ictionary.Add(name, ms);
    }
    return vm;
}

【问题讨论】:

  • 我认为您误解了锁定的作用。锁定阻止所有其他线程访问受保护的代码区域。它对 current 线程没有任何作用。你可以在同一个线程上对同一个对象取出一千次锁,没问题;因此锁定的每个代码区域都将受到保护,不会被其他线程访问。
  • 如果您正在寻找“同线程锁”,请查看 Semaphore 类。

标签: c# multithreading


【解决方案1】:

保证可以工作 - 锁在 .NET 中是递归的。这是否真的是一个好主意是另一回事……不如这样:

public Machine SomeFunction(string name) 
{ 
    lock (_dictionary)
    {
        Machine result;
        if (!_dictionary.TryGetValue(name, out result))
        {
            result = CreateMachine(name);
            _dictionary[name] = result;
        }
        return result;
    } 
}

// This is now *just* responsible for creating the machine,
// not for maintaining the dictionary. The dictionary manipulation
// is confined to the above method.
private Machine CreateMachine(string name)
{
    return new Machine(name);
}

【讨论】:

  • @Jon Skeet:只是为了验证自己,不应该尝试获取值而不是立即锁定字典?就像你只在 TryGetValue() 方法返回 false 时才锁定?
  • @Will Marcouiller - 您的方案将允许一个线程修改字典,而另一个线程正在读取它。如果字典类是专门为允许这样做而设计的,那么沿着这些思路的一些方案可能是可能的(在获得锁定后使用额外的 TryGetValue)。但是,集合通常不适合以这种方式使用,内置的 Dictionary 类是不应该同时读取和写入的类之一。
  • 感谢杰弗里的精彩解释!我会准确地发誓,我的一些同事在锁定()集合之前和之后已经使用了 TryGetValue()。那时这可能是他们的一个不好的用法。谢谢!我会记住的。 =)
【解决方案2】:

这里没问题,锁是由同一个线程重入的。并非所有同步对象都具有线程亲和性,例如 Semaphore。但是 Mutex 和 Monitor (lock) 都可以。

【讨论】:

    【解决方案3】:

    自 .net 4.0 以来的新功能,请查看 ConcurrentDictionary - ConcurrentDictionary 是一个线程安全的键/值对集合,可以由多个线程同时访问。更多信息https://msdn.microsoft.com/en-us/library/dd287191(v=vs.110).aspx

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-24
      • 1970-01-01
      • 1970-01-01
      • 2011-10-12
      • 2016-08-07
      • 1970-01-01
      • 1970-01-01
      • 2011-10-19
      相关资源
      最近更新 更多