2014-12-10 17 views
18

il seguente:C++ 11: Cosa succede se non si chiama join() per std :: filo

void test() 
{ 
    std::chrono::seconds dura(20); 
    std::this_thread::sleep_for(dura); 
} 

int main() 
{ 
    std::thread th1(test); 
    std::chrono::seconds dura(5); 
    std::this_thread::sleep_for(dura); 
    return 0; 
} 

main uscirà dopo 5 secondi, che cosa accadrà a th1 che è ancora in esecuzione?

Continua l'esecuzione fino al completamento anche se l'oggetto filetto th1 definito in main esce dall'ambito e viene distrutto?

si trova semplicemente lì dopo il completamento dell'esecuzione o in qualche modo viene ripulito quando termina il programma?

Cosa succede se il thread è stato creato in una funzione, non main - il thread rimane in attesa finché il programma non termina o quando la funzione non rientra nell'ambito?

È sicuro semplicemente non chiamare join per un thread se si desidera un qualche tipo di comportamento di timeout sul thread?

+0

Perché non ci provi? – Drop

+14

@Drop Perché non è un modo affidabile per conoscere le * garanzie *. – dyp

+0

@dyp non sta chiedendo Stackoverflow. Compilando e gestendo questo esempio a 5 linee, almeno riusciva a trovare un indizio. C'è solo una fonte di garanzie: uno standard. – Drop

risposta

16

Se non si è staccato o aderito a un thread quando il distruttore viene chiamato chiamerà std::terminate, possiamo vedere questo andando al draft C++11 standard vediamo che la sezione 30.3.1.3filo distruttore dice:

Se joinable(), chiama std :: terminate(). Altrimenti, non ha effetti. [ Nota: separare o unire implicitamente un thread joinable() in il suo distruttore può comportare errori di correttezza di debug (per errori scollegati) o prestazioni (per join) rilevati solo quando viene sollevata un'eccezione . Pertanto, il programmatore deve assicurarsi che il distruttore non venga mai eseguito mentre il thread è ancora unificabile. -end nota]

come per una motivazione per questo comportamento possiamo trovare una buona sintesi in (Not) using std::thread

Perché il distruttore di un filo joinable dovuto chiamare std :: terminare?Dopotutto, il distruttore poteva unirsi al thread secondario, oppure staccarlo dal thread secondario, oppure cancellare il thread . In breve, non è possibile partecipare al distruttore in quanto ciò comporterebbe risultato in un programma imprevisto (non indicato esplicitamente nel codice) bloccato in caso di tiri f2.

e segue un esempio e dice anche:

Non si può staccare in quanto si rischierebbe la situazione in cui thread principale lascia la portata che il thread figlio è stato lanciato nel, e il thread figlio mantiene in esecuzione e mantiene i riferimenti allo scopo che è già andato.

L'articolo fa riferimento a N2802: A plea to reconsider detach-on-destruction for thread objects che è argomento contro la proposta precedente, che era staccarsi alla distruzione se si può unire e osserva che una delle due alternative sarebbe di unirsi che potrebbe portare a situazioni di stallo l'altra alternativa è quello che abbiamo oggi che è std::terminate sulla distruzione se unificabile.

5

std::thread::~thread()

Se * questo è un thread associato (joinable() == true), std::terminate() viene chiamato

Fonte: http://en.cppreference.com/w/cpp/thread/thread/~thread

Ciò significa che programma come questo non è affatto ben formato o sicuro.

Si noti, tuttavia, che boost::thread::~thread() chiama detach() in questo caso. (come utente dyp dichiarato nei commenti, questo comportamento è deprecato nelle versioni più recenti)

si può sempre risolvere questo usando Raii. Basta avvolgere il filo in un'altra classe, che avrà un comportamento desiderato in caso di distruzione.

+2

Questo comportamento di boost è deprecato: http://www.boost.org/doc/libs/1_57_0/doc/html/thread/thread_management.html#thread.thread_management.thread.destructor – dyp

+0

@dyp Cool! Posso aggiungerlo nella mia risposta? ;) – Drop

+1

Beh, certo. Ecco perché sto facendo commenti :) – dyp

1

In C++ 11, è necessario specificare esplicitamente "cosa succede" quando il thread appena creato esce dall'ambito (il nostro nome è chiamato). A volte, quando siamo sicuri che il thread principale sta continuando, e i nostri thread agiscono come "pipeline", è sicuro "staccarli"; e qualche volta quando stiamo aspettando che i nostri thread WORKER completino le loro operazioni, ci uniamo a loro.

Come dice this, il programmatore deve assicurarsi che il distruttore non venga mai eseguito mentre il thread è ancora unificabile.

Specificare la strategia multi-thread. In questo esempio, viene chiamato std::terminate().

Problemi correlati