Domanda

Quindi, nel frattempo sappiamo che ricontrollato-bloccaggio come è non funziona in C ++, almeno non in maniera portatile.

Ho appena realizzato che ho un'implementazione fragile in un pigro-quadtree che uso per un ray tracer terreno. Così ho cercato di trovare un modo per utilizzare ancora l'inizializzazione differita in modo sicuro, come non vorrei per l'utilizzo della memoria e ri-ordinare gran parte quadruple di algoritmi implementati.

Questa attraversamento si ispira al modello a pagina 12 del C ++ e pericoli di doppio controllo Blocco , ma cerca di fare più conveniente:

(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;
                }
            }
        }
    }
}

Si presume che #pragma flush potrebbe anche servire come punto di sequenza rigido in cui compilatori e processori non potranno operazioni di riordino attraverso loro.

Quali problemi vedete?

modifica Versione 2, cercando di tener conto Vlads risposta (introdurre terzo livello):

(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;
                }
            }
        }
    }
}

modifica Versione 3, in qualche modo trovare questa bella equivalente alla versione 2, perché io non sto usando il bambino in sé, ma una bandiera primitiva per verificare la validità, sostanzialmente basandosi su una barriera di memoria tra la creazione di un bambino e la scrittura a quella bandiera.

(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;
            }
        }
    }
}
È stato utile?

Soluzione

Sembra che il vostro modello non è corretto. Si consideri il caso in cui filo # 1 esegue fino a dopo la prima #pragma flush. Quindi il controllo passa al filo # 2, che va avanti e crea un c, il controllo viene ripreso appena prima seconda #pragma flush. Ora il primo thread si sveglia, e crea il bambino di nuovo.

Edit: sorry, sbagliato:., Sarà in grado di prendere il blocco

Modifica 2: no, ancora corretta, perché il valore non sarà lavato in discussione # 1

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top