我想强制使用if-lock-if模式来检查多线程环境中字典中是否存在对象。所以,我正在考虑的代码是这样的:
private IDictionary<string, SomeType> m_dic = new Dictionary<string, SomeType>();
private SomeType GetSomeObject(string key)
{
SomeType obj;
if (!m_dic.TryGetValue(key, out obj))
{
lock(m_dic)
{
if (!m_dic.TryGetValue(key, out obj))
{
m_dic[key] = obj = CreateSomeObject(key);
}
}
}
return obj;
}
我假设即使另一个线程现在正在同一个键上插入对象,TryGetValue也不会返回部分设置的引用(这样的东西在.NET中不存在,是吗?),而不是将返回null,因此我们进入受保护的部分并重复检查。
我的问题是我的假设是正确的,代码是对的吗?
感谢。
修改
让我加入一个限制。字典实际上是单例对象的字典。因此,一旦条目被占用,它就永远不会改变。就像单例的Instance属性一样 - 一旦设置,它就永远不会改变。鉴于这种约束,我们可以使用if-lock-if模式吗?
答案 0 :(得分:5)
为清晰起见编辑:
这不是非常糟糕的想法。您可以在简单和原子(int
)上玩if-lock游戏,但是Dictionary是一个包含多个移动部件的类。阅读和写作必须始终保持同步,请参阅this MSDN page上的ThreadSafety部分。
答案 1 :(得分:3)
来自http://www.yoda.arachsys.com/csharp/singleton.html:
锁定其他类可以访问和锁定的对象(例如类型)会导致性能问题甚至死锁。这是我的一般风格偏好 - 只要有可能,只锁定专门为锁定目的而创建的对象,或者为了特定目的而锁定它们的文档(例如,等待/脉冲队列)。通常这些对象应该是它们所使用的类的私有对象。这有助于使编写线程安全的应用程序变得更加容易。
此外,双重检查锁定几乎总是一个坏主意。因此,我会使用类似于以下的代码:
private static readonly object m_padlock = new object();
private IDictionary<string, SomeType> m_dic = new Dictionary<string, SomeType>();
private SomeType GetSomeObject(string key)
{
SomeType obj;
lock (m_padlock)
{
if (!m_dic.TryGetValue(key, out obj))
{
m_dic[key] = obj = CreateSomeObject(key);
}
}
return obj;
}
答案 2 :(得分:2)
见my comments to the correct reply。重要的是:如果在示例中将Dictionary替换为Hashtable,则此方法将起作用。
答案 3 :(得分:0)
在.NET中,无法获得部分设置引用。所有读/写引用操作都是原子的。
代码看起来很好:) 但是不要忘记将同步添加到其他操作,例如INSERT和UPDATE。
答案 4 :(得分:0)
我认为ReaderWriterLock比这种情况下的方法更好。此外,你有多个读者,但只有一个作家。
http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlock.aspx