2009-08-07 14 views
22

Sto provando a scrivere un'applicazione thread piuttosto semplice, ma sono nuovo alla libreria di thread di boost. Un semplice programma di test su cui sto lavorando è:(semplice) boost thread_group question

#include <iostream> 
#include <boost/thread.hpp> 

int result = 0; 
boost::mutex result_mutex; 

boost::thread_group g; 

void threaded_function(int i) 
{ 
    for(; i < 100000; ++i) {} 

    { 
     boost::mutex::scoped_lock lock(result_mutex); 
     result += i; 
    } 
} 

int main(int argc, char* argv[]) 
{ 
    using namespace std; 

    // launch three threads 
    boost::thread t1(threaded_function, 10); 
    boost::thread t2(threaded_function, 10); 
    boost::thread t3(threaded_function, 10); 

    g.add_thread(&t1); 
    g.add_thread(&t2); 
    g.add_thread(&t3); 

    // wait for them 
    g.join_all(); 

    cout << result << endl; 

    return 0; 
} 

Tuttavia, quando ho compilare ed eseguire questo programma ho una potenza di

$ ./test 
300000 
test: pthread_mutex_lock.c:87: __pthread_mutex_lock: Assertion `mutex->__data.__owner == 0' failed. 
Aborted 

Ovviamente, il risultato è corretto, ma io sono preoccupato su questo messaggio di errore, soprattutto perché il vero programma, che ha essenzialmente la stessa struttura, si blocca sul punto join_all(). Qualcuno può spiegarmi cosa sta succedendo? Esiste un modo migliore per farlo, ovvero avviare un numero di thread, memorizzarli in un contenitore esterno e attendere che vengano completati tutti prima di continuare il programma?

Grazie per il vostro aiuto.

risposta

25

Penso che il problema sia causato dal distruttore thread_group che viene chiamato quando il programma termina. Il gruppo di thread vuole assumersi la responsabilità di distruggere gli oggetti thread. Vedi anche nella documentazione boost::thread_group.

Si stanno creando oggetti thread nello stack come variabili locali nell'ambito della funzione principale. Pertanto, sono già stati distrutti al termine dell'esecuzione del programma e thread_group tenta di eliminarli.

Come soluzione, creare i tuoi oggetti thread sul mucchio con nuova e lasciare che il thread_group prendersi cura di loro distruzione:

boost::thread *t1 = new boost::thread(threaded_function, 10); 
... 
g.add_thread(t1); 
... 
+0

È necessario rimuovere i puntini di sospensione tra la "nuova" allocazione di memoria e passarla al thread_group. Altrimenti se qualcosa va storto (cioè getta) nel codice che interviene, si perde il filo. –

+0

Sì, questo sembra essere il caso ed è stata la causa del bug nel programma più grande pure. L'esempio di lavoro ora utilizza: // avvia tre thread g.add_thread (new boost :: thread (threaded_function, 10)); g.add_thread (nuovo boost :: thread (threaded_function, 10)); g.add_thread (nuovo boost :: thread (threaded_function, 10)); – RandomGuy

+1

Un buon modo per assicurarsi che non ci siano perdite sarebbe stato usare la soluzione std :: unique_ptr o simile e usare ptr.get() per fornire il thread al group_thread. – Klaim

2

add_thread() assume la proprietà del thread passato. Il gruppo di thread elimina il thread. In questo esempio si sta eliminando la memoria allocata sullo stack, praticamente un reato capitale.

funzione dell'utente add_thread()

vuoto add_thread (filo * THRD);

Presupposto:

L'espressione eliminare THRD è ben formato e non si tradurrà in comportamento non definito.

Effetti:

la proprietà del boost :: filo oggetto puntato da THRD e inserirlo al gruppo.

Post-:

this-> size() viene aumentato di uno.

Non so se questo è ciò che è sbagliato nel codice, o se questo è solo un bug di esempio. Altrimenti il ​​codice sembra a posto.

24

Se non avete bisogno di una maniglia per il tuo thread, provare a utilizzare thread_group :: create_thread(), che riduce la necessità di gestire la discussione a tutti:

// Snip: Same as previous examples 

int main(int argc, char* argv[]) 
{ 
    using namespace std; 

    // launch three threads 
    for (int i = 0; i < 3; ++i) 
     g.create_thread(boost::bind(threaded_function, 10)); 

    // wait for them 
    g.join_all(); 

    cout << result << endl; 

    return 0; 
} 
+0

create_thread restituisce ancora un handle al thread http://www.boost.org/doc/libs/1_39_0/doc/html/thread/thread_management.html#thread.thread_management.threadgroup.create_thread. La ragione per cui create_thread può essere utilizzata in questo caso è perché a differenza di add_thread, il gruppo thread non si assume la responsabilità dell'eliminazione del thread. – shank22

0

sembra nessuno di sopra in realtà ha risposto alla domanda.

Ho incontrato il problema simile. La conseguenza di questo avviso (pthread_mutex_lock.c: 87: __pthread_mutex_lock:. Assertion `mutex -> _ dati _owner == 0' fallito Interrotto.) È che a volte il programma perdite fili e causare un'eccezione boost_resource_error.

Il motivo sembra che il programma continui ad essere eseguito dopo join_all() sebbene la maggior parte dei thread sia ancora in esecuzione (non terminata).