Pregunta

Así que, mientras tanto, sabemos que una doble comprobación de bloqueo como es que no funciona en C ++, al menos no de una manera portátil.

Me acabo de dar cuenta que tengo una aplicación frágil en un perezoso-árbol cuádruple que utilizo para un trazador de rayos terreno. Así que traté de encontrar una manera de seguir utilizando la inicialización perezosa de una manera segura, ya que no le gustaría al uso de la memoria y volviendo a comprar grandes piezas cuádruples de algoritmos implementados.

Este recorrido está inspirado en el patrón en la página 12 de C ++ y los peligros de doble Chequeado bloqueo, sino que trata de hacer que sea más barato:

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

Se supone que #pragma flush también serviría como un punto de secuencia duro donde no se les permitirá compiladores y procesadores a las operaciones de re-orden a través de ellos.

¿Qué problemas ves?

editar Versión 2, tratando de tener en cuenta las Vlads respuesta (introducir tercer ras):

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

editar Versión 3, de alguna manera encontrar este bonito equivalente a la Versión 2, porque no estoy usando el niño en sí, sino una bandera primitiva para comprobar la validez, básicamente depender de una barrera de memoria entre la creación un niño y la escritura a la bandera.

(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;
            }
        }
    }
}
¿Fue útil?

Solución

Parece que su patrón no es correcta. Considere el caso cuando hilo # 1 ejecuta hasta después de la primera #pragma flush. Entonces el control pasa al hilo # 2, que sigue y crea un c, el control es llevado de vuelta justo antes de la segunda #pragma flush. Ahora el primer hilo se despierta, y crea al niño de nuevo.

Edit: Lo siento, equivocada:. Será incapaz de tomar la cerradura

Editar 2: no, siendo correcta, ya que el valor no se enrojeció en hilo # 1

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top