Question

Alors, en attendant, nous savons que revérifié verrouillage en l'état ne fonctionne pas en C ++, du moins pas de manière portable.

Je viens de réaliser que j'ai une mise en œuvre fragile dans un quadtree paresseux que je l'utilise pour un traceur de rayons terrain. J'ai donc essayé de trouver un moyen d'utiliser encore l'initialisation paresseuse d'une manière sûre, que je ne voudrais pas quadrupler une grande partie d'utilisation de la mémoire et Réorganiser des algorithmes mis en œuvre.

Cette traversal est inspirée par le modèle à la page 12 de C ++ et les Périls de revérifié verrouillage , mais essaie de le faire moins cher:

(pseudo code!)

struct Foo {
    bool childCreated[4];
    Mutex mutex[4];
    Foo child[4];

    void traverse (...) {
        ...
        if (!childCreated[c]) { 
            // get updated view
            #pragma flush childCreated[c]
            if (!childCreated[c]) { 
                ScopedLock sl (mutex[c]);
                if (!childCreated[c]) {
                    create (c);
                    #pragma flush childCreated[c]  
                    childCreated[c] = true;
                }
            }
        }
    }
}

On suppose que #pragma flush servirait également de point de séquence difficile où les compilateurs et les processeurs ne seront pas autorisés à des opérations re ordre à travers eux.

Quels problèmes voyez-vous?

modifier Version 2, en essayant de prendre en compte Vlads de réponse (troisième place flush):

(pseudo code!)

struct Foo {
    bool childCreated[4];
    Mutex mutex[4];
    Foo child[4];

    void traverse (...) {
        ...
        if (!childCreated[c]) { 
            // get updated view
            #pragma flush childCreated[c]
            if (!childCreated[c]) { 
                ScopedLock sl (mutex[c]);
                #pragma flush childCreated[c]
                if (!childCreated[c]) {
                    create (c);
                    #pragma flush childCreated[c]
                    childCreated[c] = true;
                }
            }
        }
    }
}

modifier Version 3, je trouve en quelque sorte ce joli équivalent à 2 version, parce que je ne suis pas en utilisant l'enfant lui-même, mais un drapeau primitif pour vérifier la validité, en se fondant essentiellement sur une barrière de mémoire entre la création un enfant et écrit à ce drapeau.

(pseudo code!)

struct Foo {
    bool childCreated[4];
    Mutex mutex[4];
    Foo child[4];

    void traverse (...) {
        ...
        if (!childCreated[c]) { 
            ScopedLock sl (mutex[c]);
            #pragma flush childCreated[c]
            if (!childCreated[c]) {
                create (c);
                #pragma flush childCreated[c]
                childCreated[c] = true;
            }
        }
    }
}
Était-ce utile?

La solution

Il semble que votre modèle n'est pas correct. Prenons le cas lorsque le fil # 1 exécute jusqu'à après la première #pragma flush. Ensuite, les interrupteurs de commande au fil # 2, qui se poursuit et crée un c, le contrôle est repris juste avant la deuxième #pragma flush. Maintenant, le premier fil se réveille, et crée à nouveau l'enfant.

Edit: désolé, mal. Il ne pourra pas prendre le verrou

Edit 2: non, toujours correct, parce que la valeur ne sera pas rincée en fil # 1

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top