2013-07-29 25 views
9

Esistono due operazioni CAS CAS in C++ 11: atomic_compare_exchange_weak e atomic_compare_exchange_strong.Quando dovrebbe essere usato std :: atomic_compare_exchange_strong?

Secondo cppreference:

Le forme deboli delle funzioni sono autorizzati a sicuro falsamente, che è , agiscono come se * obj = * attesi anche se sono uguali!. Quando un confronto-e-scambio è in un ciclo, la versione debole produrrà prestazioni migliori su alcune piattaforme. Quando un confronto e scambio debole richiede e un circuito forte non lo richiede, quello forte è preferibile.

Il seguente è un esempio per l'utilizzo della deboli versione , penso:

do { 
    expected = current.value(); 
    desired = f(expected); 
} while (!current.atomic_compare_exchange_weak(expected, desired)); 

Qualcuno potrebbe dare un esempio in cui il confronto-e-scambio non è in un ciclo in modo che il è preferibile la versione forte?

+0

Sembra che questo potrebbe accadere ogni volta che l'operazione non è stata critica. Diciamo che hai un certo numero di thread di lavoro che hanno un lavoro regolare che stanno facendo, ma stanno anche controllando il lavoro aggiuntivo in una coda. Se l'operazione CAS fa sembrare che la coda non possa essere bloccata, potrebbe non essere un grosso problema, dal momento che il lavoratore può continuare a svolgere il proprio lavoro regolare. –

risposta

9

Le atomic_compare_exchange_XXX funzioni di aggiornare l'argomento "attesa" con il valore osservato, in modo che il ciclo è uguale a:

expected = current; 
do { 
    desired = f(expected); 
} while (!current.atomic_compare_exchange_weak(expected, desired)); 

Se il valore desiderato è indipendente del valore atteso, questo ciclo diventa:

desired = ...; 
expected = current; 
while (current.atomic_compare_exchange_weak(expected, desired)) 
    ; 

Aggiungiamo un po 'di semantica. Diciamo che diversi thread stanno eseguendo questo contemporaneamente. In ogni caso, desired è un ID diverso da zero per il thread corrente e current viene utilizzato per fornire l'esclusione reciproca per garantire che alcuni thread eseguano un'attività di pulizia. Non ci interessa davvero quale, ma vogliamo essere sicuri che qualche thread abbia accesso (e forse altri thread possono osservare il vincitore leggendo il suo ID da current).

Possiamo raggiungere la semantica desiderati con:

expected = 0; 
if (current.atomic_compare_exchange_strong(expected, this_thread)) { 
    // I'm the winner 
    do_some_cleanup_thing(); 
    current = 0; 
} else { 
    std::cout << expected << " is the winner\n"; 
} 

Questo è un caso in cui atomic_compare_exchange_weak richiederebbe un ciclo per ottenere lo stesso effetto atomic_compare_exchange_strong, poiché guasti spuri sono possibili:

expected = 0; 
while(!current.atomic_compare_exchange_weak(expected, this_thread) 
     && expected == 0)) 
    ; 
if (expected == this_thread) { 
    do_some_cleanup_thing(); 
    current = 0; 
} else { 
    std::cout << expected << " is the winner\n"; 
} 

Lo standard suggerisce che le implementazioni potrebbero fornire un codice più efficiente in questo caso per atomic_compare_exchange_strong rispetto al ciclo con ..._weak (§29.6.5/25 [atomics.types.operations.req]).

Problemi correlati