2014-11-27 23 views
15

Perché il programma con questo codice stampa a volte "2"?C++ equivoco lettura/scrittura incomprensibile

int main() { 
    std::atomic<int> a; 
    a = 0; 

    std::thread t1([&]{++a;}); 
    std::thread t2([&]{a++;}); 
    std::thread t3([&]{ 
     a = a.load() + 1; 
    }); 

    t1.join(); 
    t2.join(); 
    t3.join(); 

    if (a != 3) { 
     std::cout << "a: " << a << std::endl; 
    } 
} 

ho pensato std::atomic garantisce che tutte le operazioni saranno fatte in modo atomico a scrivere qui (incremento) utilizzeranno una barriera di memoria e avremo sempre 3 alla fine di fili funzionano. Ho esplorato il codice e ho scoperto che il problema è t3 ma non riesco a capire perché sia ​​sbagliato.

+8

'a = a.load() + 1' non è solo una operazione però. –

+0

++ a e a ++ non è fatto atomicamente. potresti voler dare un'occhiata a http://en.cppreference.com/w/cpp/atomic/atomic/fetch_add – Rush

+1

@Rush Che ne pensi allora? http://en.cppreference.com/w/cpp/atomic/atomic/operator_arith @ JonathanPotter L'ho pensato, ma come funziona allora l'incremento? Penso che abbia bisogno di leggerlo almeno, no? Quindi in 't3' ho provato a simularlo ma sembra che sia sbagliato come @ ParkYoung-Bae ha detto. Quindi penso che il problema è che 't3' sovrascrive con un vecchio valore. –

risposta

26

t3, a differenza degli altri due thread, non esegue un'aggiunta atomica. Al contrario, carica atomicamente a, esegue l'aritmetica (aggiungi 1) su un valore temporaneo e memorizza il nuovo valore in modo nuovo su a. Questo sovrascrive a indipendentemente dalle operazioni atomiche che potrebbero essersi verificate nel mezzo.

così si può avere il seguente scenario:

  1. t1 o t2 atomicamente incremento a che ora è uguale a 1.
  2. t3 carica atomicamente 1.
  3. t1 o t2 atomicamente incremento a che è ora uguale a 2.
  4. t3 esegue un add non atomico sul previo valore usualmente caricato e immagazzinato atomicamente indietro 2.