2010-01-26 6 views
6

Esto está haciendo en mi cabeza.G ++ CAS (__sync_val_compare_and_swap) problema necesita explicar

Estoy tratando de poner en práctica algo de código "lock-libre" y estoy usando CAS (__sync_val_compare_and_swap gcc) para hacer que levantar objetos pesados.

Mi problema se puede mostrar con el siguiente código.

volatile bool lock; 
void *locktest(void *arg) 
{ 
    for (int i = 0 ; i < 100000 ; ++i) 
    { 
     // acquire a lock 
     while(__sync_val_compare_and_swap(&lock, false, true) == true) 
     { 
      // Spin while we don't acquire 
     } 

     // make sure we have the lock 
     assert(lock == true); 

     // release the lock 
     assert(__sync_val_compare_and_swap(&lock, true, false) == true); 
    } 
} 

Ok, si ejecuto el código anterior en 10 subprocesos simultáneos, todo está bien.

Sin embargo, si cambio el código para leer

 // acquire a lock 
     while(__sync_val_compare_and_swap(&lock, lock, true) == true) 

Aviso he cambiado "falsa" para "bloquear".

el infierno se desata y la afirmación

 // make sure we have the lock 
     assert(lock == true); 

incendios. ¿Alguien puede explicar por qué esto hace la diferencia?

Thx Marca.

Respuesta

5

Me parece que __sync_val_compare_and_swap siempre devolverá el valor anterior de la variable, incluso si no se realizó ningún intercambio. En este caso, supongamos que otro hilo retiene el bloqueo justo antes de intentar adquirirlo, entonces lock es verdadero, y usted está llamando al __sync_val_compare_and_swap(&lock, true, true);. Justo antes de la comparación atómica real y el intercambio (pero después de determinar los argumentos de la función), el otro hilo libera el bloqueo: lock se convierte en falso. El compare_and_swap devolverá falso, pero no habrá realizado la operación swap, porque el valor con el que se comparó no era el valor del bloqueo. Este subproceso no realizó el intercambio, por lo que el valor de lock sigue siendo false, lo que activa su aserción.

Por cierto, sugiero hacer lock a volatile bool. No desea que el compilador optimice las referencias a tales variables.

+0

Gracias Aidan. Creo que lo has aclarado en mi mente ... Es gracioso cómo estaba tan cerca del código que ni siquiera podía pensar. Esto era un error en algunos códigos de producción e intuitivamente pensé que estaba mal, pero no podía entender por qué. – ScaryAardvark

+0

Sí, tiene razón ... Nuestro código de producción lo tiene como volátil y mi código de prueba rápida no. Enmendaré mi pregunta en consecuencia :) – ScaryAardvark

+0

Aún mejor podría ser 'volátil sig_atomic_t'. –