【发布时间】:2016-01-14 04:53:01
【问题描述】:
我正在玩 TPL,并试图通过并行读取和写入同一个字典来找出我会造成多大的混乱。
所以我有这个代码:
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));
}
}
确实很乱,抛出了很多异常,主要是key不存在,还有一些是index out of array的异常。
但是应用运行一段时间后就挂了,cpu百分比停留在25%,机器有8核。 所以我假设这是 2 个线程满负荷运行。
然后我在上面运行了 dottrace,得到了这个:
这与我的猜测相符,两个线程以 100% 运行。
都运行 Dictionary 的 FindEntry 方法。
然后我再次运行应用程序,使用dottrace,这次结果略有不同:
这一次,一个线程运行 FindEntry,另一个线程运行 Insert。
我的第一个直觉是它是死锁的,但后来我认为不可能,只有一个共享资源,它没有被锁定。
那么这应该怎么解释呢?
ps:我不是要解决这个问题,它可以通过使用 ConcurrentDictionary 或并行聚合来解决。我只是在寻找一个合理的解释。
【问题讨论】:
-
你可以猜到 Findentry 试图找到一个条目。它保留了一些稍后更改的局部变量,这导致循环结束条件永远不会终止,因为它假定由另一个线程更改的条目数不会改变。
-
所以不是死锁,而是内部状态混乱导致的死循环?
标签: c# .net multithreading parallel-processing task-parallel-library