Я играл с 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));
}
}
Это было действительно испорчено, было много исключений, в основном из-за ключа не существует, несколько из индекса, не связанного с массивом.
Но после запуска приложения какое-то время он зависает, а процент процессора остается на уровне 25%, машина имеет 8 ядер. Поэтому я предполагаю, что 2 потока работают на полную мощность.
Затем я набросился на него и получил следующее:
Он соответствует моему предположению, два потока работают со 100%.
Оба запускают метод FindEntry словаря.
Затем я снова запустил приложение, с dottrace, на этот раз результат несколько отличается:
На этот раз один поток запускает FindEntry, другой Insert.
Моя первая интуиция заключалась в том, что он мертв заблокирован, но тогда я думал, что этого не может быть, есть только один общий ресурс, и он не заблокирован.
Итак, как это объяснить?
ps: Я не пытаюсь решить проблему, ее можно исправить с помощью ConcurrentDictionary или путем параллельной агрегации. Я просто ищу разумное объяснение этого.