11
votes

Clarification de lecture et d'écriture sur un dictionnaire C #

Dans le contexte de cette déclaration,

Un dictionnaire peut supporter Plusieurs lecteurs simultanément, aussi longtemps Comme la collection n'est pas modifiée. Même si, énumérant à travers un la collecte n'est intrinsèquement pas un Procédure de fil-sécurité. Dans les rares cas où une énumération soutient avec accès à l'écriture, la collection doit être verrouillé pendant toute la énumération. Permettre la collection à accéder par plusieurs threads pour lecture et écriture, vous devez Mettre en œuvre votre propre synchronisation.

Que fait et écrire signifie? Ma compréhension est qu'une lecture est une opération qui recherche une clé et fournit une référence à sa valeur et qu'une écriture est une opération qui ajoute ou supprime une paire de valeur clé du dictionnaire. Cependant, je ne trouve rien de concluant que pour cela.

La grande question est donc la suivante, lors de la mise en œuvre d'un dictionnaire de fil de fil, une opération qui mettrait à jour la valeur d'une clé existante dans le dictionnaire soit considérée comme un lecteur ou un écrivain? Je prévois d'avoir plusieurs threads accédant à des touches uniques dans un dictionnaire et de modifier leurs valeurs, mais les threads ne vont pas ajouter / supprimer de nouvelles touches.

L'implication évidente, supposant que la modification d'une valeur existante n'est pas une opération d'écriture sur le dictionnaire, est que ma mise en œuvre de la diction diction de fil peut être beaucoup plus efficace, car je n'aurais pas besoin d'obtenir une serrure exclusive à chaque fois que je Essayez de mettre à jour la valeur à une clé existante.

L'utilisation de la simultindication de .net 4.0 n'est pas une option.


0 commentaires

6 Réponses :


2
votes

Écraser une valeur existante doit être traitée comme une opération d'écriture


2 commentaires

C'est vraiment un commentaire, pas une réponse à la question. Veuillez utiliser "Ajouter un commentaire" pour laisser des commentaires pour l'auteur.


@Sliverninja, me semble que cette réponse aborde la question principale "une opération qui met à jour la valeur d'une clé existante dans le dictionnaire soit considérée comme un lecteur ou un écrivain?".



-1
votes

Modification d'une valeur est une écriture et introduit une condition de course.

Disons la valeur initiale de MyDICT [5] = 42. Un thread met à jour le myDICT [5] à 112. Un autre fil met à jour le myDICK [5] à 837.

Quelle devrait être la valeur de la mydict [5] à la fin? L'ordre des threads est important dans ce cas, ce qui signifie que vous devez vous assurer que la commande est explicite ou qu'elles n'écrivent pas.


3 commentaires

Ce que vous décrivez n'est pas vraiment une condition de race - puisque bien de toute la manière qui le fait la dernière victoire - et ce serait identique si vous avez enfermé l'accès. Une condition de race serait quelque chose comme: si (! Dict.containskey (5)) dict (5, nouvelle valeur ()), il existe maintenant une incohérence potentielle générée.


@Neil Je pense que c'est une condition de race, juste pas une condition de race que le dictionnaire peut traiter. Je code déjà en place pour garantir que le type de condition de race mentionnée dans la réponse ne se produise pas.


@Joshua - une condition de course pourrait se produire dans le code du dictionnaire qui implémente 'myDICT [5] = x' mais il n'y a pas d'état de course existant entre les instructions de Serinus '3 définies. Qui a déjà défini la valeur la dernière victoire - c'est juste une description de la programmation normale. Une condition de course se produit dans le cas où vous définissez l'état basé sur l'examen précédemment précédemment. Sur son propre x = 1 ne peut pas générer une condition de course x ++ peut.



0
votes

Tout ce qui peut affecter les résultats d'une autre lecture doit être considéré comme une écriture.

Changer la clé d'une clé est très définitivement une écriture car elle provoquera que l'élément se déplace dans le hachage interne ou l'index ou si les dictionnaires font leurs trucs O (log (n)) ...

Ce que vous voudrez peut-être faire est de regarder ReaderWriterLock

http://msdn.microsoft.com/fr- US / Bibliothèque / System.threading.ReaderWriterLock.aspx



0
votes

3 commentaires

C'est un point intéressant, si je déclare un dictionnaire de et insérer ("key1", "bonjour") puis effectuez le répertoire ["Key1"] = "C'est une chaîne vraiment très longue", Pour réaffecter la mémoire pour la valeur ou, étant donné que la valeur est une oje, et la mémoire a déjà été allouée pour l'objet, il serait capable de réutiliser cette mémoire? Je suppose que beaucoup dépendraient des entrailles de l'objet de dictionnaire.


Pour Dictionnaire Le stockage sous-jacent est ICollection >. Le fait que vous ayez déjà inséré une valeur signifie qu'un enregistrement a été ajouté à l'ICOLLECTION (élargir son contenu, augmenter la mémoire si nécessaire). Le contenu n'est qu'une structure contenant une référence à deux objets de chaîne. Modification de la chaîne de valeur du dictionnaire en quelque chose d'autre crée simplement une nouvelle chaîne en mémoire et met à jour la référence KeyValuePair. Pas de changement sur la taille du stockage sous-jacent.


De plus, l'insertion lancera une exception si vous essayez d'insérer la même clé deux fois. Cela peut se produire facilement dans un environnement multi-fileté où le verrouillage n'était pas correctement mis en œuvre. Si vous voulez être plus sûr, il suffit d'accéder à une clé inexistante le fera de créer. Si cela existe, il sera mis à jour. Pas de lancement d'exception. Utilisez INSERT si l'ajout de la même clé est une condition d'erreur réelle que vous souhaitez attraper. annuaire.insert ("Key1", "Bonjour"); Versus Directory ["Key1"] = "Bonjour";



0
votes

Une opération de lecture est tout ce qui obtient une clé ou une valeur à partir d'un dictionnaire code>, une opération d'écriture est tout ce qui met à jour ou ajoute une clé ou une valeur. Donc, un processus mettant à jour une clé serait considéré comme un écrivain.

Un moyen simple de faire un dictionnaire Safe de thread est de créer votre propre implémentation de la marque code> code> qui verrouille simplement un mutex puis transmet le Appelez à une implémentation: p>

public class MyThreadSafeDictionary<T, J> : IDictionary<T, J>
{
      private object mutex = new object();
      private IDictionary<T, J> impl;

      public MyThreadSafeDictionary(IDictionary<T, J> impl)
      {
          this.impl = impl;
      }

      public void Add(T key, J value) 
      {
         lock(mutex) {
             impl.Add(key, value);
         }
      }

      // implement the other methods as for Add
}


1 commentaires

Y a-t-il des raisons de faire cela plutôt que d'utiliser une concurrence concurrente?



3
votes

Un point majeur non encore mentionné est que si TVALUE code> est un type de classe, les éléments détenus par un dictionnaire code> seront les identités de TVALUE code> Objets em>. Si on reçoit une référence du dictionnaire, le dictionnaire ne connaîtra ni ne se souciera de quoi que ce soit peut ne pas faire avec l'objet qui l'a fait référence à ce que l'objet mentionné ainsi.

une classe utilitaire utile utile dans des cas où toutes les clés associées à un dictionnaire seront connues À l'avance du code qui doit utiliser, c'est le cas: P>

class MutableValueHolder<T>
{
   public T Value;
}


0 commentaires