2013-02-13 21 views
7

Avevo un problema (segfault) che eseguiva un codice multithread in C++ 11. Qui è il codice:C++ 11 std :: vector in concurrent environment

#include <vector> 
#include <thread> 

std::vector<int> values; 
int i; 

void values_push_back() 
{ 
    values.push_back(i); 
} 

int main() 
{ 
    while(true) 
    { 
     std::vector<std::thread> threads; 

     for(i=0; i<10; ++i) 
     { 
      std::thread t(values_push_back); 
      threads.push_back(std::move(t)); 
     } 
     for(i=0; i<10; ++i) 
      threads[i].join(); 
    } 

    return 0; 
} 

E qui il backtrace su gdb: http://pastebin.com/5b5TN70c

Cosa c'è di sbagliato in questo?

+0

, vedere il mio commento sulla hmjds risposta e no bl Indly copia il suo codice. – inf

risposta

11

Questo non è correlato allo spostamento.

Più thread sono in esecuzione sullo stesso vector::push_back()vector ma vector::push_back() non è threadsafe. Le modifiche allo vector devono essere sincronizzate.

Un std::mutex potrebbe essere utilizzato per sincronizzare le chiamate push_back():

std::vector<int> values; 
std::mutex values_mutex; 

void values_push_back() 
{ 
    values_mutex.lock(); 
    values.push_back(i); 
    values_mutex.unlock(); 
} 

Inoltre, la variabile i è condivisa tra i thread senza sincronizzazione che si tradurrà in una condizione di competizione (un possibile risultato di questo è duplicare int s aggiunto allo vector). Considerare passando il valore int come argomento al filo per evitare questo:

std::vector<int> values; 
std::mutex values_mutex; 

void values_push_back(int i) 
{ 
    values_mutex.lock(); 
    values.push_back(i); 
    values_mutex.unlock(); 
} 

for (int i = 0; i < 10; ++i) 
{ 
    threads.push_back(std::thread(values_push_back, i)); 
} 

for (auto& t: threads) t.join(); 

Come commentato da bamboon preferiscono std::lock_guard per garantire il bloccaggio viene rilasciato se push_back() tiri (che in questo caso potrebbe essere solo bad_alloc() ma se le modifiche vector di tenere oggetti più complessi che hanno lancio costruttori diventa più importante):

void values_push_back(int i) 
{ 
    std::lock_guard<std::mutex> lk(values_mutex); 
    values.push_back(i); 
} 
+0

Ho avuto un problema più complesso che non riesco a riprodurre con un semplice codice. Mi dispiace per quello – deepskyblue86

+9

Il tuo codice non è sicuro per le eccezioni. Se push_back lancia, tieni il deadlock, invece usa 'std :: lock_guard'. – inf

+1

@bamboon, buon punto e aggiornato. – hmjd

Problemi correlati