Barrière de mémoire par instruction de locking

J’ai lu récemment des articles sur les barrières de mémoire et la question des commandes en cours et il y a maintenant une certaine confusion à ce sujet.

Considérez le scénario suivant:

private object _object1 = null; private object _object2 = null; private bool _usingObject1 = false; private object MyObject { get { if (_usingObject1) { return _object1; } else { return _object2; } } set { if (_usingObject1) { _object1 = value; } else { _object2 = value; } } } private void Update() { _usingMethod1 = true; SomeProperty = FooMethod(); //.. _usingMethod1 = false; } 
  1. Méthode de Update à Update ; L’ _usingMethod1 = true est-elle toujours exécutée avant d’obtenir ou de définir la propriété? ou en raison d’un problème de réapprovisionnement, nous ne pouvons pas garantir cela?

  2. Devrions-nous utiliser volatile comme

     private volatile bool _usingMethod1 = false; 
  3. Si nous utilisons un lock; pouvons-nous garantir alors que chaque déclaration dans le verrou sera exécutée dans l’ordre suivant:

     private void FooMethod() { object locker = new object(); lock (locker) { x = 1; y = a; i++; } } 

    Le sujet des barrières de mémoire est assez complexe. Il fait même trébucher les experts de temps en temps. Lorsque nous parlons d’une barrière de mémoire, nous combinons vraiment deux idées différentes.

    • Acquérir clôture: Une barrière de mémoire dans laquelle les autres lectures et écritures ne sont pas autorisées à se déplacer avant la clôture.
    • Libérer la clôture: Barrière de mémoire dans laquelle les autres lectures et écritures ne sont pas autorisées à se déplacer après la clôture.

    Une barrière de mémoire qui crée seulement un des deux s’appelle parfois une demi-clôture . Une barrière de mémoire qui crée les deux s’appelle parfois une barrière complète .

    Le mot clé volatile crée des demi-barrières. Les lectures de champs volatiles ont une sémantique acquise tandis que les écritures ont une sémantique de publication. Cela signifie qu’aucune instruction ne peut être déplacée avant une lecture ou après une écriture.

    Le mot clé lock crée des clôtures complètes sur les deux limites (entrée et sortie). Cela signifie qu’aucune instruction ne peut être déplacée ni avant ni après chaque limite.

    Cependant, tout cela est théorique si nous ne nous intéressons qu’à un seul thread. L’ordre, tel qu’il est perçu par ce fil, est toujours conservé. En fait, sans cette garantie fondamentale, aucun programme ne fonctionnerait jamais correctement. Le vrai problème est de savoir comment les autres threads perçoivent les lectures et les écritures. C’est là que vous devez être concerné.

    Donc pour répondre à vos questions:

    1. Du sharepoint vue d’un seul fil … oui. Du sharepoint vue d’un autre fil … non.

    2. Ça dépend. Cela pourrait fonctionner, mais je dois mieux comprendre ce que vous essayez de réaliser.

    3. Du sharepoint vue d’un autre fil … non. Les lectures et écritures sont libres de se déplacer dans les limites du verrou. Ils ne peuvent tout simplement pas sortir de ces limites. C’est pourquoi il est important que les autres threads créent également des barrières de mémoire.

    Le mot clé volatile ne fait rien ici. Il a des garanties très faibles, cela n’implique pas une barrière de mémoire. Votre code ne montre pas qu’un autre thread est créé, il est donc difficile de deviner si le locking est requirejs. Il est toutefois indispensable que deux threads puissent exécuter Update () simultanément et utiliser le même object.

    Veillez à ce que votre code de locking ne bloque rien. Chaque thread aurait sa propre instance de l’object “locker”. Vous devez en faire un champ privé de votre classe, créé par le constructeur ou un initialiseur. Ainsi:

     private object locker = new object(); private void Update() { lock (locker) { _usingMethod1 = true; SomeProperty = FooMethod(); //.. _usingMethod1 = false; } } 

    Notez qu’il y aura également une course sur l’affectation SomeProperty.