2011-07-18 54 views
9
private object lockObj = new object(); 

private Dictionary<int, string> dict = new Dictionary<int, string>(); 

public string GetOrAddFromDict(int key) 
{ 
    string value; 

    // non-locked access: 
    if (dict.TryGetValue(key, out value)) 
     return value; 

    lock (this.lockObj) 
    { 
     if (dict.TryGetValue(key, out value)) 
      return value; 

     string newValue = "value of " + key; // place long operation here 
     dict.Add(key, newValue); 

     return newValue; 
    } 
} 

问题a:线程安全吗?如果是,为什么?这个非锁定TryGetValue()字典访问线程安全吗?

问题b:这个double-TryGetValue()模式是如何调用的?

+0

旁注;对于'Hashtable',双重检查锁定*的模式显然是安全的。字典的安全性不太清楚。 –

回答

15

a)这不是线程安全的,因为底层Dictionary本身不是线程安全的。如果另一个线程同时调用Add,则会发生未定义的行为。

b)这实际上是在double-checked locking的尝试。

我建议使用ConcurrentDictionary类,因为它是为这种情况设计的。如果您不打算使用.NET 4.0,另一个选择是使用ReaderWriterLockSlim(或ReaderWriterLock)。

+0

-1 ReaderWriterLockSlim和ReaderWriterLock比'lock'贵得多,特别是在写入时。使用这些函数的唯一原因是,当你为每次写入操作执行100或1000次读取操作时,读取锁定的持续时间足以导致其他线程出现严重延迟。使用这个简单的代码(一个TryGetValue),'lock'语句就是正确的同步。 –

+2

@ csharptest.net这很苛刻;他的建议是'ConcurrentDictionary',这很好 - 而且由于里德不是OP,**我们不知道**读者/写者的比率。对于我们所知道的,“ReaderWriterLockSlim”实际上可能没有问题。 –

+1

@csharptest以下博客条目声称''ReaderWriterLockSlim'比'Monitor'的性能开销大约是一个因子2.从您的评论中我预计超过10的因子。http://blogs.msdn.com/b/pedram/archive /2007/10/07/a-performance-comparison-of-readerwriterlockslim-with-readerwriterlock.aspx – CodesInChaos

2

不幸的是,没有。

我带着一个具有这个属性的自定义HashMap。

缺陷位于rehash()函数中。

9

问题a:线程安全吗?如果是,为什么?

它不仅不是线程安全的;如果在另一个线程正在重新组织散列桶时访问,它也会抛出NullReferenceException异常。锁定语句很快,不要回避它。

问题b:这个double-TryGetValue()模式是如何调用的?

它之所以被称为 '臭虫' 被大多数人;)

+1

*这被大多数人称为'bug'*让我失望LOL +1)+1 –