De tenter de synchroniser l'interne sera presque certainement être insuffisant car il est à un niveau trop bas de l'abstraction. Dire que vous faites l' Add
et ContainsKey
opérations thread-safe comme suit:
public void Add(TKey key, TValue value)
{
lock (this.syncRoot)
{
this.innerDictionary.Add(key, value);
}
}
public bool ContainsKey(TKey key)
{
lock (this.syncRoot)
{
return this.innerDictionary.ContainsKey(key);
}
}
Puis ce qui se passe lorsque vous appelez cette soi-disant "thread-safe" peu de code à partir de plusieurs threads? Il travaille toujours OK?
if (!mySafeDictionary.ContainsKey(someKey))
{
mySafeDictionary.Add(someKey, someValue);
}
La réponse simple est non. À un certain point l' Add
méthode lève une exception indiquant que la clé existe déjà dans le dictionnaire. Comment cela peut-il être avec un dictionnaire thread-safe, vous pourriez demander? Eh bien tout simplement parce que chaque opération est thread-safe, la combinaison de deux opérations n'est pas, comme un autre thread pourrait modifier entre votre appel à l' ContainsKey
et Add
.
Ce qui signifie écrire ce type de scénario correctement, vous avez besoin d'un verrou à l'extérieur le dictionnaire, par exemple
lock (mySafeDictionary)
{
if (!mySafeDictionary.ContainsKey(someKey))
{
mySafeDictionary.Add(someKey, someValue);
}
}
Mais maintenant, en voyant que vous êtes d'avoir à écrire de l'extérieur à un code de verrouillage, vous êtes de mélange interne et externe de synchronisation, ce qui conduit toujours à des problèmes tels que floues code et de blocages. Si, finalement, vous êtes probablement mieux à soit:
Utiliser une normale Dictionary<TKey, TValue>
et la synchronisation en externe, en joignant le composé opérations sur elle, ou
Écrire un nouveau thread-safe wrapper avec une interface différente (c'est à dire pas IDictionary<T>
) qui combine les opérations telles que l' AddIfNotContained
méthode vous n'avez jamais besoin de combiner des opérations.
(J'ai tendance à aller avec le n ° 1 de moi-même)