2013-08-12 30 views
1

我試圖重現不「保存線程」字典行爲 和實施示例(見下文)。 我期待死鎖,但測試沒有任何問題。 請你能幫我解釋一下我的測試中有什麼問題,以及如何模擬多線程字典錯誤。如何模擬「安全線程」字典行爲?

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Threading; 
using System.Threading.Tasks; 
using Microsoft.VisualStudio.TestTools.UnitTesting; 

namespace parallelTest 
{ 
    [TestClass] 
    public class UnitTest1 
    { 
     Dictionary<int, string> dictionary = new Dictionary<int, string>(); 
     [TestMethod] 
     public void TestMethod1() 
     { 
      dictionary[2000] = "test"; 

      Parallel.For(0, 1000, i => 
      { 
       string value; 
       dictionary.TryGetValue(2000, out value); 
       dictionary[2000] = String.Format("new value {0}", i); 
       dictionary.Add(i, String.Format("{0}", i)); 
       Trace.WriteLine(String.Format("thread: {0}, {1}, {2}", Thread.CurrentThread.ManagedThreadId, i, value)); 
       Thread.Sleep(100); 
      } 
      ); 
     } 
    } 
} 
+3

開始刪除睡眠(),但它仍然不會做你想做的。不安全 - >競賽條件 - >未定義的行爲。你可以期待各種錯誤,但沒有死鎖。 –

+0

我開始沒有睡眠的測試:沒有任何錯誤 – constructor

+0

我的生產代碼中有一個「死鎖」問題(看起來在Get Dictionaty中)。現在我調查這個問題。 – constructor

回答

1

由於Dictionary未鎖定其內部數據,因此不能面臨死鎖。
儘管您可能會在字典中出現意外的數據。在這種情況下:未添加的項目。

你需要檢查字典是否如你所期望的那樣在壓力測試之後。

for(Int32 index=0; index < 1000; index++) 
{ 
    if(dictionary.Values.Any(index.ToString()) == false) 
    { 
      // problem 
    } 

} 

順便說一句,如果你想強調字典,你需要刪除函數中的所有其他操作,例如的String.Format。通過這樣做,您將增加在字典中創建問題的機會。

這是在您調用public add方法時調用的內部方法,正如您所看到的那樣,那裏沒有鎖。

private void Insert(TKey key, TValue value, bool add) 
{ 
    if (key == null) 
    { 
     ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key); 
    } 
    if (this.buckets == null) 
    { 
     this.Initialize(0); 
    } 
    int num = this.comparer.GetHashCode(key) & 2147483647; 
    int num2 = num % this.buckets.Length; 
    int num3 = 0; 
    for (int i = this.buckets[num2]; i >= 0; i = this.entries[i].next) 
    { 
     if (this.entries[i].hashCode == num && this.comparer.Equals(this.entries[i].key 
                    , key)) 
     { 
      if (add) 
      { 
       ThrowHelper.ThrowArgumentException(ExceptionResource 
                 .Argument_AddingDuplicate); 
      } 
      this.entries[i].value = value; 
      this.version++; 
      return; 
     } 
     num3++; 
    } 
    int num4; 
    if (this.freeCount > 0) 
    { 
     num4 = this.freeList; 
     this.freeList = this.entries[num4].next; 
     this.freeCount--; 
    } 
    else 
    { 
     if (this.count == this.entries.Length) 
     { 
      this.Resize(); 
      num2 = num % this.buckets.Length; 
     } 
     num4 = this.count; 
     this.count++; 
    } 
    this.entries[num4].hashCode = num; 
    this.entries[num4].next = this.buckets[num2]; 
    this.entries[num4].key = key; 
    this.entries[num4].value = value; 
    this.buckets[num2] = num4; 
    this.version++; 
    if (num3 > 100 && HashHelpers.IsWellKnownEqualityComparer(this.comparer)) 
    { 
     this.comparer = (IEqualityComparer<TKey>)HashHelpers 
            .GetRandomizedEqualityComparer(this.comparer); 
     this.Resize(this.entries.Length, true); 
    } 
} 

我希望它有幫助。