Pourquoi les objets immuables sont-ils thread-safe?

class Unit {
    private readonly string name;
    private readonly double scale;

    public Unit(string name, double scale) {
        this.name = name;
        this.scale = scale,
    }

    public string Name { get { return name; } }
    public string Scale { get { return scale; } }

    private static Unit gram = new Unit("Gram", 1.0);

    public Unit Gram { get { return gram; } }
}

Plusieurs threads ont accès à Unit.Gram. Pourquoi est-ce correct pour plusieurs threads lus simultanément Unit.Gram.Title?

Ma préoccupation est qu'ils font référence au même emplacement de mémoire. Un fil commence à lire cette mémoire, alors n'est-ce pas "verrouillé" alors? Est - ce que le. net gère la synchronisation pour cette section critique en dessous? Ou Ai-je tort de penser que la lecture simultanée a besoin de synchronisation?

30
demandé sur randomguy 2010-08-29 18:28:53

8 réponses

Je pense que votre question ne concerne pas la sécurité des threads ou l'immuabilité, mais les détails (très) bas niveau de l'accès à la mémoire.

Et c'est un sujet lourd mais la réponse courte est: oui, deux threads (et plus important, 2+ CPU) peuvent lire (et/ou écrire) le même morceau de mémoire simultanément.

Et tant que le contenu de cette zone de mémoire est immuable, tous les problèmes sont résolus. Quand il peut changer, il y a toute une gamme de problèmes, le mot-clé volatile et le Interlocked class sont quelques-uns des outils que nous utilisons pour les résoudre.

11
répondu Henk Holterman 2010-08-29 16:11:50

Qu'est-ce qui rend un objet non sécurisé? Un objet n'est pas thread safe si la valeur/l'état de cet objet peut changer pendant qu'un thread le lit. Cela se produit généralement si un deuxième thread change la valeur de cet objet pendant que le premier thread le lit.

Un objet immuable, par définition, ne peut pas changer de valeur / d'état. Puisque chaque fois que vous lisez un objet immuable, il a la même valeur / état, vous pouvez avoir n'importe quel nombre de threads lire cet objet sans problème.

57
répondu Starkey 2010-08-29 14:35:46

Lectures Simultanées ne besoin de synchronisation. Comme la synchronisation n'est requise que pour les écrivains (ou les lecteurs et au moins un écrivain), les objets immuables ne nécessitent pas de synchronisation et sont donc threadsafe.

11
répondu Gabe 2010-08-29 14:38:00

Si l'objet est immuable, son état ne changera jamais. Par conséquent, les préoccupations des données périmées sortent de la fenêtre. La lecture de Thread n'est jamais verrouillée, donc c'est un non-problème (deadlock)

4
répondu Woot4Moo 2010-08-29 14:36:51

Les lectures simultanées ne nécessitent pas de synchronisation dans la grande majorité des cas (les exceptions sont des choses comme les e / s mappées en mémoire où la lecture à partir d'une certaine adresse peut provoquer des effets secondaires).

Si les lectures simultanées nécessitaient une synchronisation, il serait presque impossible d'écrire du code multithread utile. Pour exécuter un morceau de code par exemple, le processeur doit lire le flux d'instructions, comment écririez-vous une fonction de verrouillage si la fonction elle-même devait se protéger contre lui-même étant exécuté simultanément:)?

3
répondu Logan Capaldo 2010-08-29 14:39:00

La lecture du même emplacement mémoire ne peut être effectuée que dans un cycle CPU par un thread spécifique. L'ordre de lecture dans ce cas n'a pas d'importance puisque la valeur sous-jacente ne change pas. Par conséquent, il n'y a aucune possibilité qu'une lecture soit incohérente, donc il n'y a pas besoin de synchronisation à n'importe quel niveau dans ce cas.

2
répondu venky 2010-08-29 17:21:35

Gestion de la Mémoire Unités de sont la partie du processeur qui gère la lecture de la mémoire. Si vous en avez plus d'un, une fois dans une lune bleue 2 d'entre eux pourraient essayer de lire le même emplacement de mémoire dans la même douzaine de nano-secondes, mais aucun problème ne résulte car ils obtiennent la même réponse.

1
répondu Gordon Gustafson 2010-08-29 14:39:02

Outre les exceptions comme la mémoire mappée pour les pilotes par exemple, il n'y a pas de problème pour deux threads lisant simultanément la même adresse mémoire. Un problème peut survenir lorsqu'un thread effectue des écrivant des données. Dans ce cas, d'autres threads peuvent être empêchés de lire cet objet/ces données.

Mais le problème n'est pas dû à la simultanéité des écrits (au niveau électronique le plus bas ils se produisent l'un après l'autre de toute façon), le problème est plutôt que objet / Ensemble de données peut perdre leur cohérence. Habituellement, on utilise un section critic pour isoler du code qui peut ne pas être lu / écrit simultanément par d'autres threads.

Il y a beaucoup d'exemples sur le Net, mais considérez ce qui suit, avec price est un membre privé d'une classe, disons Product, qui a aussi 2 méthodes

public void setPrice(int value) {
  price = value;
  // -- point CRITIC --
  price += TAX;
}

public int getPrice() {
  return price;
}

SetPrice (v) définit le prix d'un produit sur v, et l'ajuste avec la TVA (le programme devrait avoir value += TAX; price = value mais ce n'est pas le point ici: -)

Si le fil A écrit le prix 100, et la taxe est (fixe) 1, le prix du produit sera finalement réglé sur 101. Mais que se passe-t-il si le thread B Lit le prix via getPrice() alors que le thread A est à point CRITIC? Le prix retourné à B va manquer la taxe, et être faux.

SetPrice () devrait dans une section critique (lock), pour empêcher tout accès à l'objet pendant la fixation du prix

    lock(this)
    {
      price = value;
      price += TAX;
    }
1
répondu Ring Ø 2010-08-29 15:11:12