我正在玩TPL,並試圖找出我可以通過同時閱讀和寫入同一個詞典來得到多大的混亂。.Net中的Dictionary可能會在並行讀取和寫入時導致死鎖?
所以我有這樣的代碼:
private static void HowCouldARegularDicionaryDeadLock()
{
for (var i = 0; i < 20000; i++)
{
TryToReproduceProblem();
}
}
private static void TryToReproduceProblem()
{
try
{
var dictionary = new Dictionary<int, int>();
Enumerable.Range(0, 1000000)
.ToList()
.AsParallel()
.ForAll(n =>
{
if (!dictionary.ContainsKey(n))
{
dictionary[n] = n; //write
}
var readValue = dictionary[n]; //read
});
}
catch (AggregateException e)
{
e.Flatten()
.InnerExceptions.ToList()
.ForEach(i => Console.WriteLine(i.Message));
}
}
這是非常搞砸確實,有很多拋出的異常的,主要是關於鍵不存在,一些有關索引越界陣列的。
但運行應用程序一段時間後,它掛起,並且CPU百分比保持在25%,機器有8個內核。 所以我認爲這是2個線程滿負荷運行。
然後我跑它dottrace,並得到了這一點:
據我的猜測一致,兩個線程運行在100%。
都運行Dictionary的FindEntry方法。
然後我再次運行應用程序,與dottrace,這一次的結果略有不同:
這個時候,一個線程在運行FindEntry,其他的插入。
我的第一個直覺是它已經死鎖了,但後來我認爲它不可能,只有一個共享資源,並沒有鎖定。
那麼應該如何解釋?
ps:我不想解決問題,它可以通過使用ConcurrentDictionary或通過並行聚合來解決。我只是在尋找一個合理的解釋。
正如你所猜測的,Findentry試圖找到一個條目。它保留了一些稍後改變的局部變量,這導致循環結束條件永遠不會終止,因爲它假定由另一個線程改變的條目計數沒有改變。 –
所以它不是一個死鎖,而是一個由內部狀態混亂造成的無限循環? – CuiPengFei
是........... – pm100