Como mostrar que o padrão de bloqueio com verificação dupla com TryGetValue do dicionário não é seguro para threads
Recentemente, vi alguns projetos C # que usam um padrão de bloqueio com verificação dupla em umDictionary
. Algo assim:
private static readonly object _lock = new object();
private static volatile IDictionary<string, object> _cache =
new Dictionary<string, object>();
public static object Create(string key)
{
object val;
if (!_cache.TryGetValue(key, out val))
{
lock (_lock)
{
if (!_cache.TryGetValue(key, out val))
{
val = new object(); // factory construction based on key here.
_cache.Add(key, val);
}
}
}
return val;
}
Este código está incorreto, pois oDictionary
pode estar "crescendo" a coleção em_cache.Add()
enquanto_cache.TryGetValue
(fora da trava) está iterando sobre a coleção. Pode ser extremamente improvável em muitas situações, mas ainda está errado.
Existe um programa simples para demonstrar que esse código falha?
Faz sentido incorporar isso em um teste de unidade? E se sim, como?