2010-01-26 8 views
6

Questo sta facendo la testa.G ++ CAS (__sync_val_compare_and_swap) problema deve spiegare

Sto cercando di implementare un codice "lock-libero" e sto usando CAS (gcc __sync_val_compare_and_swap) per fare che sollevamento di carichi pesanti.

Il mio problema può essere visualizzato con il seguente codice.

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, se eseguo il codice sopra in 10 thread simultanei, tutto va bene.

Tuttavia, se cambio il codice per leggere

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

Avviso ho cambiato "false" a "bloccare".

scatena l'inferno e l'affermazione

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

incendi. Qualcuno può spiegare perché questo fa la differenza?

Thx Mark.

risposta

5

Mi sembra che __sync_val_compare_and_swap restituisca sempre il vecchio valore della variabile, anche se non è stato effettuato alcun swap. In questo caso, supponiamo che un altro thread trattiene il blocco appena prima di provare ad acquisirlo, quindi lock è true e stai chiamando __sync_val_compare_and_swap(&lock, true, true);. Subito prima dell'effettivo confronto e scambio atomico (ma dopo aver determinato gli argomenti della funzione), l'altro thread rilascia il blocco - lock diventa falso. Il compare_and_swap restituirà false, ma non avrà eseguito l'operazione swap, perché il valore che ha confrontato non era il valore nel blocco. Questo thread non ha eseguito lo scambio, quindi il valore di lock rimane false, attivando l'asserzione.

Per inciso, consiglio vivamente di effettuare lock a volatile bool. Non vuoi che il compilatore ottimizzi i riferimenti a tali variabili.

+0

Grazie Aidan. Penso che tu abbia chiarito tutto nella mia mente .. È strano come fossi così vicino al codice che non riuscivo nemmeno a pensare. Questo era un bug in qualche codice di produzione e intuitivamente pensavo che fosse sbagliato ma non potevo per la vita di me capire perché. – ScaryAardvark

+0

Sì, hai ragione. Il nostro codice di produzione lo ha come volatile e il mio codice di prova veloce no. Modificherò la mia domanda di conseguenza :) – ScaryAardvark

+0

Ancora meglio potrebbe essere "volatile sig_atomic_t'. –